require "Common/define"
require "Logic/Config"
require "Common/functions"
require "Common/EnumConst"
require "Battle/Entity/SpineEffect"
require "Battle/Entity/EntityEffect"
require "Battle/Entity/EntityShadow"
require "Battle/BattleSceneCacheResouce"
Entity = {};
Entity.__index = Entity;
Entity.___no = 1;

local cacheVec1 = Vector3(0, 0, 0)
local cacheVec2 = Vector3(0, 0, 0)
local cacheVec3 = Vector3(0, 0, 0)
local buffFrontKey = 1;
local buffBackKey = 2;
local delayDeadTime = (EnumConst.FIGHT_FRAME / EnumConst.THOUSANDTH) * 3;--延时死亡时间 3帧

function Entity:new(roleInfo, isBloodBar)
    ---@class Entity
    local object = {};
    object.isBloodBar = isBloodBar;

    if roleInfo ~= nil then
        object.partnerId = roleInfo.partnerId;
        object.partnerModelId = roleInfo.partnerModelId;
        object.skinId = roleInfo.skinId;
        object.isEmpty = roleInfo.isEmpty;
        if (not object.isEmpty) then
            HeroManager.copyHeroConfigbyModelId(object.partnerModelId, object)
            object.isHero = roleInfo.isHero;
        else
            object.isHero = false
        end
        if roleInfo.isAlternate then
            object.isAlternate = true;
        else
            object.isAlternate = false;
        end
        object.fighterId = roleInfo.fighterId;
        object.hp = roleInfo.hp;
        object.maxHP = roleInfo.maxHP;
        object.energy = roleInfo.energy;
        object.maxEnergy = roleInfo.maxEnergy;
        object.shield = roleInfo.shield;
        object.teamIndex = roleInfo.teamIndex;
        object.weaponLevel = roleInfo.weaponLevel;
        object.RenderQueueRate = object.fighterId / 10000 * -1
    end
    object.modelName = "";
    ---@type UnityEngine.GameObject
    object.roleObj = nil;

    --object.skillFObj = nil;
    --object.skillFObj1 = nil;
    --object.skillBObj = nil;
    --object.hitFObj = nil;
    --object.hitBObj = nil;
    --object.bulletFObj = nil;
    --object.bulletBObj = nil;
    object.skillEffect = {};

    object.isBegin = false;
    object.isDead = false;
    object.isWaitDeadDam = false; --死了，等伤害，等动画帧触发的伤害
    object.flip = false;
    object.isDeading = false;
    object.element = 0;
    object.scale = Vector3.one;
    object.isBoss = false;
    object.heroType = 0;
    object.skeletonAnimation = nil;
    object.skeletonAnimationTrans = nil;

    --动作
    object.duration = 0;
    object.stopFrame = 0;
    object.stopDuration = 0;
    object.aniState = Config.AnimationState.IDLE;
    object.aniStateNew = Config.AnimationState.IDLE;
    object.actionName = "";
    object.actionOnlyId = nil;--当前动作唯一id
    object.isLoop = 0;

    --移动
    object.speedWalk = 1;
    object.speedRun = 1;
    object.moveDirection = Vector3(1, 0, 0);
    object.moveBegin = Vector3(0, 0, 0);
    object.moveEnd = Vector3(0, 0, 0);
    object.moveTarget = nil;
    object.moveType = EnumConst.MoveType.NONE;

    --击飞
    object.hitFlyTime = 0;
    object.hitFlyDuration = 0;
    object.normalHeight = 300;
    object.velocity = 0;
    object.acceleration = 0;

    --击退
    object.repulseTime = 0;
    object.repulseDuration = 0;
    object.repulseVelocity = 0;
    object.repulsePos = nil;

    --血条、吟唱条、怒气条、护盾
    object.headBar = nil;
    object.hpSlider = nil;--白色底
    object.hp2Slider = nil;--hp
    object.hp3Slider = nil;--mp
    object.green = nil;
    object.red = nil;
    object.spBar = nil;
    object.spTable = {};
    --object.spSlider = nil;
    --object.singBar = nil;
    --object.singSlider = nil;
    object.hasEnergy = 0;
    object.singTime = 0;
    object.shield = 0;
    object.hpTimer = nil;
    object.hideHPTime = 10;
    object.hp3Timer = nil;
    object.BloodTime = 0.5;--2 * 0.5;
    object.buffIcon = nil;

    --协程
    object.playCoroute = nil;
    object.hitCoroute = nil;

    --战斗
    object.target = nil;
    object.normalSkill = {};
    object.canAttack = true;
    object.shape = Vector2.zero;
    object.attackShape = Vector2.zero;

    --战斗特殊表现
    object.attackShowType = EnumConst.AttackShowType.NONE;
    object.attackValue = nil;
    object.attackShowDuration = 0;
    object.attackMoveSpeed = 0;
    object.attackDirection = nil;
    object.attackMoveEnd = nil;
    object.showDead = false

    --受击特殊表现
    object.hitShowType = EnumConst.HitShowType.NONE;
    object.hitValue = nil;
    object.hitShowDuration = 0;
    object.maxHitShowDuration = 0;
    object.hideTransitionTime = 0;
    object.maxHideTime = 0;
    object.hitMoveSpeed = 0;
    object.hitDirection = nil;

    --buffs
    object.buffSigns = {};
    object.buffs = {};
    object.buffEffect = {};
    object.buffDatas = {};--需要人物配合动作的
    object.buffsOverlay = {};--有层数的

    --shader effect
    object.entityEffect = nil;
    object.afterImageTab = {};

    --shadow
    object.shadow = nil;
    object.lihuiSkeleton = nil;--场景内放技能出立绘

    --锚点
    object.boneTransforms = nil;
    object.bones = nil;

    --role 灵敏度（默认为1， [0, 某正数]）
    object.timeScale = 1;

    --攻速
    object.attackSpeed = 1;

    -- 缓存
    object.SpineEffectCacheList = {}

    object.delayCallFunc = nil
    object.delayCallDuration = 0;
    object.battleInfoStr = "";
    --distortion effect
    object.distortionEffect = nil;
    object.isMask = false;--英雄是否消失
    object.isHook = false;--英雄是否被拖拽
    object.isShowDamage = true;--是否飘字
    object._localPosition = Vector3.New()
    object._worldPosition = Vector3.New()
    object.fighterClass = nil;--客户端战斗逻辑英雄类
    --英雄子弹时间
    object.cutInTime = 0;
    --英雄渐隐时间
    object.fadeTime = 0;
    --当前渐隐时间
    object.curFadeTime = 0;
    --飞行状态
    object.isFly = false;

    object.NO = Entity.___no;
    Entity.___no = Entity.___no + 1;

    setmetatable(object, Entity);
    return object;
end

function Entity:init()
    if self.headBar ~= nil then
        --if not self.isHero then
            self:setHeadBar(false);
        --else
        --self:setHeadBar(true)
        --end
        if self.isBegin then
            self.hpCtrl.selectedIndex = 1
        end
        if not self.isHero then
            local heroInfo = HeroManager.GetHeroConfigbyModelId(self.partnerModelId)
            if heroInfo.f_Type ~= 0 and self.model ~= "h040" and self.modelId ~= "203" then
                --不是格雷的复制
                Util.Lua_SetLocalScaleXYZ(self.headBar.container.gameObject.transform, 0.7, 0.7, 0.7)
            end
            self.headBar.container.gameObject.transform:Find("ty_nqc_00").gameObject:SetActive(false)
        end
    end
    --self.hp = self.totalAttribute[EnumConst.FighterAttributeEnum.HP];
    self.isDead = false;
    self.needDead = false;--死亡标签 若标签为true 并且血量归0则死亡
    self.isWaitDeadDam = false;
    self.isDeading = false;
    if self.teamIndex == 2 then
        --1队的玩家队，进来就是move进场，2队的需要初始化状态
        self.aniStateNew = Config.AnimationState.IDLE;
        self.aniState = Config.AnimationState.IDLE;
        self:playAction("idleBattle");
    end

    if (not Util.IsNull(self.skeletonAnimation) and not Util.IsNull(self.skeletonAnimation.Skeleton)) then
        self.skeletonAnimation.Skeleton.A = 1;
        --强制spine更新一帧刷新状态
        --self.skeletonAnimation:Update(0);
    elseif not self.isEmpty then
        --local str = self.roleObj and self.roleObj.name or "";
        --printError("Skeleton有问题", "name = " .. str);
    end
end

function Entity:destroy()
    if self.delayCallFunc then
        self.delayCallFunc = nil;
        self.delayCallDuration = 0;
    end

    if self.mysayTimeId then
        ubattletimer.remove(self.mysayTimeId)
        self.mysayTimeId = nil
    end

    if self.sayCtrlTimer then
        ubattletimer.remove(self.sayCtrlTimer)
        self.sayCtrlTimer = nil
    end

    if self.sayTimeId then
        ubattletimer.remove(self.sayTimeId)
        self.sayTimeId = nil
    end

    if self.headBar ~= nil then
        UIBloodBar.RemoveBloodBar(self.headBar);
        if self.ubattletimer then
            ubattletimer.remove(self.ubattletimer);
            self.ubattletimer = nil;
        end
        --destroy(.displayObject.gameObject);
        self.headBar = nil;
    end

    if self.roleObj ~= nil then
        destroyImmediate(self.roleObj)
        self.roleObj = nil;
    end

    if self.shadow then
        self.shadow:destroy();
    end

    self:RemoveAllEffect();

    if self.entityEffect then
        self.entityEffect:clear();
        self.entityEffect = nil;
    end
    if self.lihuiSkeleton then
        --destroyImmediate(self.lihuiSkeleton.gameObject.transform.parent.gameObject);
        self.lihuiSkeleton = nil;
    end
    self.skeletonAnimationTrans = nil
    self._localPosition = nil
    self._worldPosition = nil
end

function Entity:onDeadEnd()
    self.isDead = true;
    self.isWaitDeadDam = false;
    self.roleObj:SetActive(false);
    if self.headBar then
        self:setHeadBar(false, false)
        UIBloodBar.RemoveBloodBar(self.headBar);
    end
    self:RemoveAllEffect();

    if self.entityEffect then
        self.entityEffect:clear();
    end
end

function Entity:initAvatar(parent, callback)
    if (self.isEmpty) then

        goEmpty = GameObject.New("goEmpty_" .. self.teamIndex .. "_" .. self.fighterId);
        self:LoadModePrefabHelper("goEmpty", goEmpty, parent, callback)
        --if(callback ~= nil)then
        --    callback();
        --end
    else
        local heroCfg = G.dataTable["t_hero"][tostring(self.partnerModelId)];
        self.moveSpeed = heroCfg.f_HeroMoveSpeed;--速度保持与服务器一致，不需要自己加速
        self.heroType = heroCfg.f_HeroType;
        self.f_LifeBar = tonumber(heroCfg.f_LifeBar or '0')
        local size = heroCfg.f_HeroSize --decodeJsonStrToTabel(heroCfg.f_HeroSize);
        if type(size) == "table" then
            self.shape = Vector2(size[1], size[2]);
        else
            self.shape = Vector2(1, 1);
        end

        local roleCfg = G.dataTable["t_roleconfig"][tostring(self.model)];
        if roleCfg ~= nil then
            self.roleCfg = roleCfg;
            self.speedWalk = Entity:GetTableValue(roleCfg, "speedWalk");
            self.speedRun = Entity:GetTableValue(roleCfg, "speedRun");
            self.hasEnergy = tonumber(Entity:GetTableValue(roleCfg, "Energy")) == 1;
            local offsetBar = Entity:GetTableValue(roleCfg, "BloodBar_Position");
            if offsetBar == nil or offsetBar == "" then
                offsetBar = 0;
            end
            self.modelName = Entity:GetTableValue(roleCfg, "modelName");

            self.offsetBar = offsetBar * FightManager.getScaleParam(parent);
            self.normalSkill = roleCfg["nomalSkill"]--decodeJsonStrToTabel(roleCfg["nomalSkill"]);
            --[[
            local normalAttackID = string_split(Entity:GetTableValue(roleCfg,"nomalSkill"),",");
            for i =1,#normalAttackID do
                table.insert(self.normalSkill, normalAttackID[i]);
            end
            ]]
        elseif not self.isEmpty then
            printError("roleconfig is nil, model==" .. self.model);
        end
        local path = HeroManager.GetHeroDrawingRolePath(self.partnerModelId, nil, self.skinId)
        local loadedObj = BattleSceneCacheResouce:GetCacheObj(path)
        if loadedObj then
            self:LoadModePrefabHelper(path, loadedObj, parent, callback)
        else
            resMgr:LoadModelPrefab(path, function(obj1)
                local role = newObject(obj1);
                self:LoadModePrefabHelper(path, role, parent, callback)
            end);
        end

        self.aniState = Config.AnimationState.IDLE;
    end
end

function Entity:LoadModePrefabHelper(path, role, parent, callback)
    BattleSceneCacheResouce:AddCacheObj(path, role)
    if parent ~= nil then
        role.transform:SetParent(parent);
    end
    --role.transform.name = self.model;

    -- 此处操作用不是很大，会有gc产生，先注释
    -- if (string.match(role.gameObject.name, "_") == nil) then
    -- 	role.gameObject.name = role.gameObject.name .. "_" .. self.teamIndex .. "_" .. self.fighterId;
    -- end

    Util.Lua_SetLocalPositionXYZ(role, 0, 0, 0);
    Util.Lua_SetLocalRotationXYZ(role, 40, 0, 0);
    --风暴峡湾boss
    local bossCfg = logicMgr.TrialsManager.GetBossConfigById(self.partnerModelId);
    if bossCfg ~= nil or logicMgr.GuildManager.checkIsGuildBossByModelId(self.partnerModelId) or FightManager.checkSoloBoss(self.partnerModelId) then
        self.isBloodBar = false;
        if FightManager.checkSoloBoss(self.partnerModelId) and logicMgr.SoloChaosTestManager.getNowBossId() ~= logicMgr.SoloChaosTestManager.getEndLessBossId() then
            self.isBloodBar = true;
        end
        self.isBoss = true;
        local scalar = FightManager.getScaleParam(parent) * FightManager.bossScale;
        local tempScale = self.scale;
        Util.Lua_SetLocalScaleXYZ(role, tempScale.x * scalar * self.shape.x, tempScale.y * scalar * self.shape.y, tempScale.z * scalar);
    else
        self.isBoss = false;
        local scalar = FightManager.getScaleParam(parent)
        local tempScale = self.scale;
        Util.Lua_SetLocalScaleXYZ(role, tempScale.x * scalar * self.shape.x, tempScale.y * scalar * self.shape.y, tempScale.z * scalar);
    end

    --
    --role.name = self.fighterId..'#' .. role.name;

    self.roleObj = role;

    if self.isEmpty then
        self:setFlip(self.teamIndex == 2);
    else
        local aniTrans = Util.Lua_SetGameObjectChildLocalEularXYZ(self.roleObj, "Animation", 0, 0, 0);
        Util.Lua_SetLocalPositionXYZ(aniTrans, 0, 0, self.RenderQueueRate);
        self.skeletonAnimationTrans = aniTrans;
        self.skeletonAnimation = aniTrans.gameObject:GetComponent(TSkeletonAnimation);

        setLayer(self.roleObj.gameObject, LayerMask.NameToLayer("role"));
        self:setFlip(self.teamIndex == 2);
        --Util.SetFlipX(self.roleObj.transform:Find("Animation").gameObject, self.flip);

        --local skinName = (self.roleCfg or {}).skin;
        --if skinName ~= nil and skinName ~= '' then
        --    --logMy('setskin', self.modelName, skinName)
        --    Util.SetSkin(aniTrans.gameObject, skinName);
        --end
        --没有就给默认值，defualt或者skin1,这个名字要统一
        --local level = logicMgr.EquipManager.getWeaponLevelByModelId(self.partnerModelId);
        --Util.SetSkin(aniTrans.gameObject, "skin"..level);
        local rank = BattlePlaybackManager.GetWeaponRankByModelId(self.partnerModelId)
        logicMgr.EquipManager.setWeaponSkin(aniTrans.gameObject, self.partnerModelId, self.teamIndex == 1, rank);

        self:updateFlip();
        --self:initBoneTrans();
        self:initBones();
        self:setOrder(Config.SortingDefault.Role);

        --local hpBar = self.roleObj.transform:Find("Attachs/BarHp");
        --hpBar.gameObject:SetActive(false);
        --local mpBar = self.roleObj.transform:Find("Attachs/BarMp");
        --mpBar.gameObject:SetActive(false);
        --local shiledBar = self.roleObj.transform:Find("Attachs/BarShiled");
        --if shiledBar ~= nil then
        --    shiledBar.gameObject:SetActive(false);
        --end

        self.entityEffect = EntityEffect:new(self.roleObj, self.fighterId);
        self.entityEffect:init();

        --shadow
        self.shadow = EntityShadow:new();
        self.shadow:init(self);

        if self.roleObj ~= nil and self.isBloodBar then
            --local headBar = newObject(prefabobj);
            --headBar.transform:SetParent(self.roleObj.transform);
            --local headBar = newGComponent("Headbar", "BattleItems");
            local headBar = UIBloodBar.GetBloodBar();
            --headBar.displayObject.gameObject.transform:SetParent(self.roleObj.transform);
            --headBar.displayObject.gameObject.layer = 10;
            --local objHeadBar = headBar.transform:Find("GameObject").gameObject
            local objHeadBarTop = headBar:GetChild("Top");
            local objHPSlider = nil;
            local objHP2Slider = headBar:GetChild("Mask_Shield");
            local objHP3Slider = nil;
            local hpController = headBar:GetController("c1");
            self.sayCtrl = headBar:GetController("LeftRight")
            self.hpCtrl = headBar:GetController("headShow")
            local sayTxt_L = headBar:GetChild("Text_HeroTalkL")
            local sayTxt_R = headBar:GetChild("Text_HeroTalkR")
            local teamIndex = self.teamIndex;
            headBar.gameObjectName = self.fighterId .. self.partnerModelId;

            if FightManager.fightType == EnumConst.FightTypeConst.RankBattle or FightManager.fightType == EnumConst.FightTypeConst.FriendAttack
                    or FightManager.fightType == EnumConst.FightTypeConst.GuildBattlePlus or FightManager.fightType == EnumConst.FightTypeConst.SoloChaosTest then
                teamIndex = FightManager.teamRest[self.teamIndex];
            else
                teamIndex = self.teamIndex;
            end
            if not self.myDialogModeId then
                self.myDialogModeId, self.sayConfig = FightManager.modelID, FightManager.modeVal
            end
            if teamIndex == 1 then
                if self.sayConfig and self.myDialogModeId and self.partnerModelId == tostring(self.myDialogModeId) and not self.isAlternate then
                    if self.sayCtrl then
                        self.sayCtrlTimer = ubattletimer.timeCall(function()
                            self:setHeadBar(true)
                            self.sayCtrl.selectedIndex = 1
                            if self.sayCtrlTimer then
                                ubattletimer.remove(self.sayCtrlTimer)
                                self.sayCtrlTimer = nil
                            end
                        end, 0.1 * 1 * EnumConst.THOUSANDTH / FightManager.curTimeScale, 1)
                        --我方出场时机
                    end
                    sayTxt_L.text = getLanguage(self.sayConfig[2])
                else
                    if self.sayCtrl then
                        self.sayCtrl.selectedIndex = 0
                    end
                end
                hpController.selectedIndex = 1;
                objHPSlider = headBar:GetChild("Mask1_1");
                objHP3Slider = headBar:GetChild("Mask3_1");
            else
                hpController.selectedIndex = 0;
                objHPSlider = headBar:GetChild("Mask1_2");
                objHP3Slider = headBar:GetChild("Mask3_2");
            end
            local speed = GetPlayerPrefs("UIBattleMainSpeed" .. logicMgr.HeroManager.GetRoleInfo("playerId"));
            local num = FightManager.timeScaleLv_1
            if speed == 1 then
                num = 3
            elseif speed == 2 then
                num = 7.5
            end
            self.mysayTimeId = ubattletimer.timeCall(function()
                if not HelperFunc.IsNull(self.sayCtrl) then
                    if teamIndex == 1 and self.sayCtrl then
                        self.sayCtrl.selectedIndex = 0
                    else
                        if self.sayConfig and self.partnerModelId == tostring(self.sayConfig[1]) then
                            if self.sayCtrl then
                                self.sayCtrl.selectedIndex = 2
                            end
                            if not HelperFunc.IsNull(sayTxt_R) then
                                sayTxt_R.text = getLanguage(self.sayConfig[3])
                            end
                        else
                            if self.sayCtrl then
                                self.sayCtrl.selectedIndex = 0
                            end
                        end
                    end
                end
                ubattletimer.remove(self.mysayTimeId)
                self.mysayTimeId = nil
            end, 2900 * num, 1)
            --我方气泡消失时间（毫秒）
            self.sayTimeId = ubattletimer.timeCall(function()
                if teamIndex == 2 and self.sayCtrl then
                    self.sayCtrl.selectedIndex = 0
                end
                self.myDialogModeId, self.sayConfig = nil, nil
                ubattletimer.remove(self.sayTimeId)
                self.sayTimeId = nil
            end, 4500 * num, 1)
            --敌方气泡消失时间（毫秒）
            --local objHPGreen = headBar:GetChild("GameObject/Top/HP/Mask/green").gameObject;
            --local objHPRed = headBar:GetChild("GameObject/Top/HP/Mask/red").gameObject;
            --local objSPBar = headBar.transform:Find("Energy").gameObject;
            local objSPSlider = headBar:GetChild("Energy");
            --local objSingBar = headBar.transform:Find("GameObject/Top/Sing").gameObject;
            --local objSingSlider = headBar.transform:Find("GameObject/Top/Sing/Mask").gameObject:GetComponent("Image");
            local objBuffImg = headBar:GetChild("Buff");
            objHeadBarTop.y = objHeadBarTop.y - self.offsetBar;
            headBar.y = self.offsetBar;
            self.headBar = headBar;
            self.headBarSkillShow = headBar:GetChild("skillShow"):GetChild("skilItem"):GetChild("Icon");--释放终结技显示的技能图标
            self.headBarSkillShowEffect = headBar:GetChild("effect_overhit");
            self.headBarSkillShowEffect.visible = false;
            headBar:GetChild("skillShow").visible = false;
            self.headBarSkillShowAni = headBar:GetTransition("overhit_in"); --释放终结技显示技能图标动画
            local effect = self.headBar:GetChild("n12");
            effect.visible = false;
            --初始化击杀表现
            self.killNum = nil;

            --self.headBar.gameObjectName = self.model;
            self.hpSlider = objHPSlider;
            self.hp2Slider = objHP2Slider;
            self.hp2Slider.value = 0;
            self.hp3Slider = objHP3Slider;
            --self.green = objHPGreen;
            --self.red = objHPRed;
            self.spSlider = objSPSlider;
            --self.spBar = objSPBar;
            --self.spTable = tab_SP;
            self.buffIcon = objBuffImg;
            --self.singBar = objSingBar;
            --self.singSlider = objSingSlider;
            if not self.isHero then
                self:setHeadBar(false);
            else
                self:setHeadBar(true);
            end
            if self.hasEnergy then
                self.spSlider.visible = true;
                --self.spBar:SetActive(true);
            else
                self.spSlider.visible = false;
                --self.spBar:SetActive(false);
            end
            self:setShield(0, 0);
            self:setHP(self.hp, self.maxHP);
            self:setSP(self.energy);
            self.buffIcon.visible = false;

            self:onUpdateBar();

            if self.lihuiSkeleton == nil and self.isAlternate and self.partnerModelId ~= "610" then
                self.isPa = false;
                local modelId = self.partnerModelId;
                if modelId == "611" then
                    modelId = "61";
                end
                local skinId = logicMgr.SkinManager.getHeroSkinId(modelId);
                if self.skinId then
                    skinId = self.skinId;
                end
                local cfg = dataTable.getDataTableByStringId("t_skin", skinId)
                local paUrl = cfg.f_FightAnim_PA
                for w in string.gmatch(paUrl, "_pa") do
                    self.isPa = true;
                end
                local url = "Prefabs/Battle/lihuiAnim";
                if AppConst.drawingState ~= 0 and self.isPa then
                    --和谐版替补立绘
                    url = "Prefabs/Battle/lihuiAnim_pa";
                end

                resMgr:LoadModelPrefab(url, function(obj1)
                    local panel = newObject(obj1);
                    if self.roleObj ~= nil then
                        panel.transform:SetParent(self.roleObj.transform);
                    end

                    Util.Lua_SetLocalRotationXYZ(panel, 0, 0, 0);
                    Util.Lua_SetLocalScaleXYZ(panel, self.scale.x * self.shape.x, self.scale.y * self.shape.y, self.scale.z);

                    setLayer(panel.gameObject, LayerMask.NameToLayer("role"));
                    --self:setOrder(Config.SortingDefault.Role);
                    Util.SetOrder(panel.transform:Find("Animation").gameObject, Config.SortingDefault.Role);

                    local aniTrans = panel.transform:Find("Animation");
                    self.lihuiSkeleton = aniTrans.gameObject:GetComponent(TSkeletonAnimation);
                    if not HelperFunc.IsNull(self.lihuiSkeleton) then
                        self.lihuiSkeleton.gameObject:SetActive(false);
                    end
                end);
            else
                if not HelperFunc.IsNull(self.lihuiSkeleton) then
                    self.lihuiSkeleton.gameObject:SetActive(false);
                end
            end
        end
    end

    self.roleObj:SetActive(false);
    if callback ~= nil then
        callback();
    end

    self.aniState = Config.AnimationState.IDLE;
end

function Entity:onUpdate(deltaTime)
    if self.isEmpty or not self.roleObj or self.isDead then
        return ;
    end
    if self.curFadeTime > 0 then
        self.curFadeTime = self.curFadeTime - deltaTime;
        if self.curFadeTime <= 0 then
            self.curFadeTime = 0;
        end
        self:setHeadBar(false);
        self.skeletonAnimation.Skeleton.A = self.curFadeTime / self.fadeTime;
        self.shadow.skeletonAnimation.Skeleton.A = self.curFadeTime / self.fadeTime;
    end

    if not EntityAiManager.updateAi(self, deltaTime) then
        --更新状态机状态
        if self.aniStateNew ~= self.aniState then
            if self.aniState == Config.AnimationState.WALK then
                --防止还没走到位置就被打断
                Util.Lua_SetLocalPositionXYZ(self.roleObj, self.moveEnd.x, self.moveEnd.y, self.moveEnd.z);
            end
            if self.aniStateNew == Config.AnimationState.START then
                self.duration = self:playAction(Config.AnimationStateName.START, false);
            elseif self.aniStateNew == Config.AnimationState.STUN then
                self.duration = 0;
                self:playAction(Config.AnimationStateName.STUN);
            elseif self.aniStateNew == Config.AnimationState.HURT then
                self.duration = self:playAction(Config.AnimationStateName.HURT, false);
                if (self.hitShowDuration > self.duration) then
                    self.duration = self.hitShowDuration;
                end
            elseif self.aniStateNew == Config.AnimationState.FREEZY or self.aniStateNew == Config.AnimationState.PETRIFACTION then
                self:PauseCurrentAction()
            elseif self.aniStateNew == Config.AnimationState.RUN then
                self.duration = 0;
                self:playAction(Config.AnimationStateName.RUN);
            elseif self.aniStateNew == Config.AnimationState.WALK then
                self.duration = 0;
                self:playAction(Config.AnimationStateName.WALK);
            elseif self.aniStateNew == Config.AnimationState.ATTACK then
                self.duration = self:playAnimation(self.actionName, self.isLoop, -1, true);
                if self.attackShowType == EnumConst.AttackShowType.SPRINT_POS then
                    --定点冲锋技能
                    self.duration = 0;
                end
                --logMy(self.name,'播放攻击',self.duration,self.isLoop,FightManager.frame)
            elseif self.aniStateNew == Config.AnimationState.DEAD then
                self.showDead = true
                FireEvent(Config.EventType.Drop_GoldAndExp, self.roleObj.transform);
                self.duration = self:playAction(Config.AnimationStateName.DEAD, false);
                local roleCfg = G.dataTable["t_roleconfig"][tostring(self.model)];
                if roleCfg.deadDelay then
                    self.stopFrame = self.duration - roleCfg.deadDelay[1] / 1000;
                    self.stopDuration = roleCfg.deadDelay[1] / 1000;
                else
                    self.stopFrame = 0;
                    self.stopDuration = 0;
                    if not Util.IsNull(self.skeletonAnimation) and not Util.IsNull(self.shadow.skeletonAnimation) then
                        Util.SetActionTimeScale(self.skeletonAnimation, self.skeletonAnimation.AnimationName, self.timeScale);
                        Util.SetActionTimeScale(self.shadow.skeletonAnimation, self.shadow.skeletonAnimation.AnimationName, self.timeScale);
                    end
                end
            elseif self.aniStateNew == Config.AnimationState.VICTORY then
                self.timeScale = 1;--胜利动作不加速
                self.duration = self:playAction(Config.AnimationStateName.VICTORY, false);
            elseif self.aniStateNew == Config.AnimationState.HITFLY then
                self.duration = self:playAction(Config.AnimationStateName.HITFLY, false, self.hitFlyTime);
                if (self.hitShowDuration > self.duration) then
                    self.duration = self.hitShowDuration;
                end
            elseif self.aniStateNew == Config.AnimationState.HITDOWN then
                self.duration = self:playAction(Config.AnimationStateName.HITDOWN, false, self.hitFlyTime);
                if (self.hitShowDuration > self.duration) then
                    self.duration = self.hitShowDuration;
                end
            elseif self.aniStateNew == Config.AnimationState.IDLE then
                self:playAction(Config.AnimationStateName.IDLE);
            else
                logMy("动画状态机 未处理状态", self.aniStateNew)
            end
            self.aniState = self.aniStateNew;

            if self.isLoop then
                self.duration = 0;
            end
        else
            if self.aniStateNew == Config.AnimationState.IDLE then
                self:onUpdateBar();
            end
        end

        --每个循环动画状态单独控制细节
        if self.aniState == Config.AnimationState.RUN then
            if self.moveType == EnumConst.MoveType.NONE then
                cacheVec1.x, cacheVec1.y, cacheVec1.z = Util.Lua_GetLocalPositionXYZ(self.roleObj, 0, 0, 0);
                self.moveDirection = Vector3.Normalize(self.moveEnd - cacheVec1);
            elseif self.moveType == EnumConst.MoveType.Target then
                if self.moveTarget ~= nil and self.moveTarget.roleObj ~= nil then
                    cacheVec1.x, cacheVec1.y, cacheVec1.z = Util.Lua_GetLocalPositionXYZ(self.moveTarget.roleObj, 0, 0, 0);
                    self.moveEnd = Vector3(cacheVec1.x, cacheVec1.y, cacheVec1.z);
                    cacheVec1.x, cacheVec1.y, cacheVec1.z = Util.Lua_GetLocalPositionXYZ(self.roleObj, 0, 0, 0);
                    self.moveDirection = Vector3.Normalize(self.moveEnd - cacheVec1);
                else
                    cacheVec1.x, cacheVec1.y, cacheVec1.z = Util.Lua_GetLocalPositionXYZ(self.roleObj, 0, 0, 0);
                    self.moveEnd = Vector3(cacheVec1.x, cacheVec1.y, cacheVec1.z);
                    self.aniStateNew = Config.AnimationState.IDLE;
                    self.aniState = Config.AnimationState.IDLE;
                    self:playAction(Config.AnimationStateName.IDLE);

                end
            elseif self.moveType == EnumConst.MoveType.Direction then
            else
            end

            cacheVec1.x, cacheVec1.y, cacheVec1.z = Util.Lua_GetLocalPositionXYZ(self.roleObj, 0, 0, 0);
            if self.moveType == EnumConst.MoveType.NONE or self.moveType == EnumConst.MoveType.Target then
                if Vector3.Distance(self.moveEnd, cacheVec1) <= deltaTime * self.speedRun * self.timeScale then
                    Util.Lua_SetLocalPositionXYZ(self.roleObj, self.moveEnd.x, self.moveEnd.y, self.moveEnd.z);
                    self.aniStateNew = Config.AnimationState.IDLE;
                    self.aniState = Config.AnimationState.IDLE;
                    self:playAction(Config.AnimationStateName.IDLE);
                else
                    local tempPos = cacheVec1 + self.moveDirection * deltaTime * self.speedRun * self.timeScale;
                    Util.Lua_SetLocalPositionXYZ(self.roleObj, tempPos.x, tempPos.y, tempPos.z)
                end
            elseif self.moveType == EnumConst.MoveType.Direction then
                local tempPos = cacheVec1 + self.moveDirection * deltaTime * self.speedRun * self.timeScale;
                Util.Lua_SetLocalPositionXYZ(self.roleObj, tempPos.x, tempPos.y, tempPos.z);
            end

            local flip = false;
            if self.moveTarget ~= nil then
                flip = getRoleFlip(self, self.moveTarget);
            else
                if self.moveDirection.x > 0 then
                    flip = false;
                elseif self.moveDirection.x == 0 then
                    flip = self.flip;
                else
                    flip = true;
                end
            end
            self:setFlip(flip);
            self:onUpdateBar();
        elseif self.aniState == Config.AnimationState.WALK then
            if self.moveType == EnumConst.MoveType.NONE then
                cacheVec1.x, cacheVec1.y, cacheVec1.z = Util.Lua_GetLocalPositionXYZ(self.roleObj, 0, 0, 0);
                self.moveDirection = Vector3.Normalize(self.moveEnd - cacheVec1);
            elseif self.moveType == EnumConst.MoveType.Target then
                if self.moveTarget ~= nil then
                    cacheVec1.x, cacheVec1.y, cacheVec1.z = Util.Lua_GetLocalPositionXYZ(self.moveTarget.roleObj, 0, 0, 0);
                    self.moveEnd = Vector3(cacheVec1.x, cacheVec1.y, cacheVec1.z);
                    cacheVec1.x, cacheVec1.y, cacheVec1.z = Util.Lua_GetLocalPositionXYZ(self.roleObj, 0, 0, 0);
                    self.moveDirection = Vector3.Normalize(self.moveEnd - cacheVec1);
                end
            elseif self.moveType == EnumConst.MoveType.Direction then
            else
            end
            cacheVec1.x, cacheVec1.y, cacheVec1.z = Util.Lua_GetLocalPositionXYZ(self.roleObj, 0, 0, 0);
            if self.moveType == EnumConst.MoveType.NONE or self.moveType == EnumConst.MoveType.Target then
                if Vector3.Distance(self.moveEnd, cacheVec1) <= deltaTime * self.moveSpeed * self.timeScale then
                    Util.Lua_SetLocalPositionXYZ(self.roleObj, self.moveEnd.x, self.moveEnd.y, self.moveEnd.z);
                    if not FightSelect.isShowSaveReport then
                        self.aniStateNew = Config.AnimationState.IDLE;
                        self.aniState = Config.AnimationState.IDLE;
                        self:playAction(Config.AnimationStateName.IDLE);
                    end
                else
                    Vec3Mul(self.moveDirection, deltaTime * self.moveSpeed * self.timeScale, cacheVec2);
                    Vec3Add(cacheVec1, cacheVec2, cacheVec2);
                    self:revisePosition(cacheVec2);
                end
            elseif self.moveType == EnumConst.MoveType.Direction then
                Vec3Mul(self.moveDirection, deltaTime * self.moveSpeed * self.timeScale, cacheVec2);
                Vec3Add(cacheVec1, cacheVec2, cacheVec2);
                self:revisePosition(cacheVec2);
            end

            local flip = false;
            if self.moveTarget ~= nil then
                flip = getRoleFlip(self, self.moveTarget);
            else
                if self.moveDirection.x > 0 then
                    flip = false;
                elseif self.moveDirection.x == 0 then
                    flip = self.flip;
                else
                    flip = true;
                end
            end
            self:setFlip(flip);
            self:onUpdateBar();
        elseif self.aniState == Config.AnimationState.ATTACK then
            cacheVec1.x, cacheVec1.y, cacheVec1.z = Util.Lua_GetLocalPositionXYZ(self.roleObj, 0, 0, 0);
            if self.attackShowType == EnumConst.AttackShowType.MOVE then
                if self.attackShowDuration > 0 then
                    self.attackShowDuration = self.attackShowDuration - deltaTime;
                    Vec3Mul(self.attackDirection, deltaTime * self.attackMoveSpeed, cacheVec2);
                    Vec3Add(cacheVec1, cacheVec2, cacheVec2);
                    self:revisePosition(cacheVec2);
                    if self.attackShowDuration < 0 then
                        self.attackShowType = EnumConst.AttackShowType.NONE;

                    end
                end
            elseif self.attackShowType == EnumConst.AttackShowType.Back then
                if self.attackShowDuration > 0 then
                    self.attackShowDuration = self.attackShowDuration - deltaTime;
                    Vec3Mul(self.attackDirection, deltaTime * self.attackMoveSpeed, cacheVec2);
                    Vec3Add(cacheVec1, cacheVec2, cacheVec2);
                    self:revisePosition(cacheVec2);
                    if self.attackShowDuration < 0 then
                        self.attackShowType = EnumConst.AttackShowType.NONE;
                    end
                end
            elseif self.attackShowType == EnumConst.AttackShowType.Protect or self.attackShowType == EnumConst.AttackShowType.SPRINT or self.attackShowType == EnumConst.AttackShowType.SPRINT_POS then
                self.attackMoveDelayTime = self.attackMoveDelayTime - deltaTime;

                local rotation = 0;
                local rotation_z = 0;
                ----Y

                local rotationPos = self.targetPos - cacheVec1
                if self.attackShowType == EnumConst.AttackShowType.SPRINT_POS then
                    rotationPos = self.attackMoveEnd - cacheVec1;
                end
                if not self.flyHold then
                    if rotationPos.x < 0 then
                        rotation = math.atan(rotationPos.z / math.abs(rotationPos.x)) / math.pi * 180;
                        rotation = -rotation;
                    else
                        rotation = math.atan(rotationPos.z / math.abs(rotationPos.x)) / math.pi * 130;

                    end
                end
                local s = self.speed;
                local dt = Time.deltaTime;
                if self.partnerModelId == "610" or self.partnerModelId == "10" or self.partnerModelId == "9001" or self.isRotation then
                    rotation = 0;
                end
                self.sprintRotation = rotation
                --Util.Lua_GameObjectAddPosAndSetRot(self.shadow.skeletonAnimation.gameObject, 0, 0, 0, 40, 0, 90-rotation);
                --printError(self.name,rotation)

                Util.Lua_GameObjectAddPosAndSetRot(self.skeletonAnimation.gameObject, 0, 0, 0, 40, 0, self.sprintRotation);


                --if not self.flyHold then
                --    rotation = math.atan(rotationPos.z / math.abs(rotationPos.x)) / math.pi * 180;
                --    if rotationPos.x > 0 then
                --        rotation = -rotation;
                --    end
                --
                --    if rotationPos.x > 0 then
                --        rotation_z = math.atan(rotationPos.y / math.abs(rotationPos.x)) / math.pi * 180;
                --    end
                --end
                --
                --local s = rotationPos;
                --local dt = Time.deltaTime;
                --Util.Lua_GameObjectAddPosAndSetRot(self.roleObj, 0, 0, 0, 40, rotation, rotation_z);

                if self.attackMoveDelayTime <= 0 then
                    --logMy('self.attackMoveDelayTime <= 0', deltaTime * self.attackMoveSpeed);
                    --self:showAfterimge(self.attackMoveSpecialEffect, deltaTime);
                    self.attackDuration = self.attackDuration - deltaTime;

                    if self.attackDuration <= 0 then
                        self:revisePosition(self.attackMoveEnd);

                        self.attackShowType = EnumConst.AttackShowType.NONE;
                        self.sprintRotation = nil;
                        --printError(self.name,"rotation 0")
                        Util.Lua_GameObjectAddPosAndSetRot(self.skeletonAnimation.gameObject, 0, 0, 0, 40, 0, 0);
                        self.timeScale = FightManager.curTimeScale;
                        --self.attackMoveSpecialEffect = nil;
                    else
                        local addPos = Vector3(rotationPos.x * (deltaTime / self.attackDuration), 0, rotationPos.z * (deltaTime / self.attackDuration));

                        --Vec3Mul(self.attackDirection, rotationPos * (deltaTime/ self.attackDuration ) , cacheVec2);
                        --Vec3Add(addPos, cacheVec2, cacheVec2);
                        Util.Lua_GameObjectAddPosAndSetRot(self.roleObj, addPos.x, addPos.y, addPos.z, 40, 0, 0);

                    end
                end
            elseif self.attackShowType == EnumConst.AttackShowType.Flash then
            elseif self.attackShowType == EnumConst.AttackShowType.FullScreen then
            else
            end
            self:onUpdateBar();
        elseif self.aniState == Config.AnimationState.HURT or self.aniState == Config.AnimationState.HITFLY then
            if self.hitShowType == EnumConst.HitShowType.REPULSE or self.hitShowType == EnumConst.HitShowType.PULL then
                if self.hitShowDuration > 0 then
                    self.hitShowDuration = self.hitShowDuration - deltaTime;
                    cacheVec1.x, cacheVec1.y, cacheVec1.z = Util.Lua_GetLocalPositionXYZ(self.roleObj, 0, 0, 0);
                    Vec3Mul(self.hitDirection, deltaTime / self.maxHitShowDuration, cacheVec2);
                    Vec3Add(cacheVec1, cacheVec2, cacheVec2);
                    self:revisePosition(cacheVec2);
                    if self.hitShowDuration < 0 then
                        self.hitShowType = EnumConst.HitShowType.NONE;
                    end
                end
            end
            if self.hitShowTypeHitFly == EnumConst.HitShowType.HITFLY then
                if self.hitShowDurationHitFly > 0 then
                    self.hitShowDurationHitFly = self.hitShowDurationHitFly - deltaTime;
                    local t = (self.hitShowTime - self.hitShowDurationHitFly) / self.hitShowTime;
                    if t > 0.8 and self.aniState == Config.AnimationState.HURT then
                        self:setAniState(Config.AnimationState.HITFLY);
                    end
                    t = t * 1.01 * 2 - 1.01;  -- 0.5 * gt * t + 5 = 0  ---> -1.01, 1.01
                    local d = -9.8 * 0.5 * t * t + 5;
                    local tempPos = self.hitShowOriginalPosition + Vector3(0, d, 0);
                    Util.Lua_SetLocalPositionXYZ(self.roleObj, self.roleObj.transform.localPosition.x, tempPos.y, tempPos.z);

                    if self.hitShowDurationHitFly <= 0 then
                        self.hitShowTypeHitFly = EnumConst.HitShowType.NONE;
                        self:recoverPosition();
                        --self:setAniState(Config.AnimationState.HITFLY);
                    end
                    --logMy('Config.AnimationState.HITFLY ---', self.hitFlyDuration, t, d);
                end

            else

            end
            self:onUpdateBar();
        end

        --状态结束 切回idleBattle
        if self.duration > 0 or (self.aniState == Config.AnimationState.START and self.duration == 0) then
            if self.duration <= self.stopFrame and self.stopDuration > 0 then
                self.stopDuration = self.stopDuration - deltaTime;

                if self.stopDuration <= 0 then
                    if not Util.IsNull(self.skeletonAnimation) and not Util.IsNull(self.shadow.skeletonAnimation) then
                        Util.SetActionTimeScale(self.skeletonAnimation, self.skeletonAnimation.AnimationName, self.timeScale);
                        Util.SetActionTimeScale(self.shadow.skeletonAnimation, self.shadow.skeletonAnimation.AnimationName, self.timeScale);

                    end
                else
                    if not Util.IsNull(self.skeletonAnimation) and not Util.IsNull(self.shadow.skeletonAnimation) then
                        Util.SetActionTimeScale(self.skeletonAnimation, self.skeletonAnimation.AnimationName, 0);
                        Util.SetActionTimeScale(self.shadow.skeletonAnimation, self.shadow.skeletonAnimation.AnimationName, 0);
                    end
                end
            else
                self.duration = self.duration - deltaTime;
            end
            if self.duration <= 0 then
                if self.aniState == Config.AnimationState.ATTACK then
                    if self.attackShowType == EnumConst.AttackShowType.FullScreen then
                        self:revisePosition(self.attackMoveEnd);
                        self.attackShowType = EnumConst.AttackShowType.NONE;
                    end
                end
                --printError("名字<--",self.name,"新状态",self.aniStateNew,"当前状态",self.aniState);
                self.aniStateNew = Config.AnimationState.IDLE;
                self.aniState = Config.AnimationState.IDLE;
                --printError("名字--",self.name,"新状态",self.aniStateNew,"当前状态",self.aniState);

                self:playAction(Config.AnimationStateName.IDLE);
                if self.isDeading then
                    self:onDeadEnd();
                end
            end
        end
        if self.delayCallFunc then
            --强制死亡倒计时；
            self.delayCallDuration = self.delayCallDuration - delayDeadTime;
            if self.delayCallDuration <= 0 then
                self.delayCallFunc();
            end
        end
    end
end

function Entity:updateEffect(deltaTime)
    if self.entityEffect then
        self.entityEffect:onUpdate(deltaTime);
    end

    if self.distortionEffect then
        self.distortionEffect.time = self.distortionEffect.time + deltaTime;
        if self.distortionEffect.time >= self.distortionEffect.delayTime then
            --logMy('distortionEffect',  self.distortionEffect.time);
            Entity.DoPlayDistortionEffect(self.distortionEffect.followInfo, self.distortionEffect.effectInfo);
            self.distortionEffect = nil;
        end
    end
end

function Entity:revisePosition(vPos)
    --return vPos;

    local x = vPos.x;
    local y = vPos.y;
    local z = vPos.z;
    if not EntityAiManager.checkAIRole(self) then
        if x > EnumConst.FIGHT_INNER_ROUND[2][1] then
            x = EnumConst.FIGHT_INNER_ROUND[2][1];
        elseif x < EnumConst.FIGHT_INNER_ROUND[1][1] then
            x = EnumConst.FIGHT_INNER_ROUND[1][1];
        end

        if z > EnumConst.FIGHT_INNER_ROUND[1][3] then
            z = EnumConst.FIGHT_INNER_ROUND[1][3];
        elseif z < EnumConst.FIGHT_INNER_ROUND[2][3] then
            z = EnumConst.FIGHT_INNER_ROUND[2][3];
        end
    end
    Util.Lua_SetLocalPositionXYZ(self.roleObj, x, y, z)
end

------------------动作------------------
function Entity:setAniState(aniState, actionName, isLoop, breakAni, onlyId)

    --printError("名字",self.name,"新状态",aniState,"当前状态",self.aniState);
    if not FightManager.entranceFinish then
        --入场人物速度
        self.timeScale = 1;
    end
    --if self.isFly and actionName then
    --    actionName = actionName.."_1";
    --end
    self.LastHitDownTime = self.LastHitDownTime or 0
    if self.isDeading then
        return ;
    end
    if breakAni == nil then
        breakAni = false;
    end

    if EntityAiManager.setAiAniState(aniState, self, actionName) then
        return ;
    end

    if aniState == Config.AnimationState.HITDOWN then
        self.LastHitDownTime = os.time()
    end

    if aniState == Config.AnimationState.STUN or aniState == Config.AnimationState.HURT or aniState == Config.AnimationState.IDLE then
        if self.LastHitDownTime and os.time() - self.LastHitDownTime < 1 then
            return
        end
    end
    local changeAniLevel = Config.FightActionTypeLevel[aniState];--新状态的优先级
    local curAniLevel = Config.FightActionTypeLevel[self.aniState];--当前状态的优先级
    if self.aniStateNew ~= self.aniState then
        curAniLevel = Config.FightActionTypeLevel[self.aniStateNew];--当前状态的优先级
    end
    if changeAniLevel > curAniLevel and not breakAni then
        --当前状态优先级大于
        return ;
    end
    if self.isSuperArmor and aniState == Config.AnimationState.HURT then
        return ;
    end
    --
    ----被击打，做以下动作，不切换动画状态。处理状态互斥，但是这样处理还是会有问题的。无优先级，无层级控制。
    --if aniState == Config.AnimationState.HURT and not breakAni then
    --    if self.aniState == Config.AnimationState.WALK or self.aniState == Config.AnimationState.RUN then
    --        return ;
    --    elseif self.aniState == Config.AnimationState.ATTACK then
    --        return ;
    --    elseif self.aniState == Config.AnimationState.HITFLY then
    --        return ;
    --    elseif self.aniState == Config.AnimationState.HIDE then
    --        return ;
    --    elseif self.aniState == Config.AnimationState.HURT then
    --        self.aniState = Config.AnimationState.IDLE;
    --    end
    --end
    --
    ----动画优先级：击飞>击倒>击退>眩晕>
    --if self.aniState == Config.AnimationState.HITFLY and not breakAni then
    --    if aniState == Config.AnimationState.HITDOWN then
    --        return ;
    --    elseif aniState == Config.AnimationState.REPULSE then
    --        return ;
    --    elseif aniState == Config.AnimationState.STUN then
    --        return ;
    --    end
    --end
    ----动画优先级：击倒>击退>眩晕>
    --if self.aniState == Config.AnimationState.HITDOWN and not breakAni then
    --    if aniState == Config.AnimationState.REPULSE then
    --        return ;
    --    elseif aniState == Config.AnimationState.STUN then
    --        return ;
    --    end
    --end
    --
    ----动画优先级：击退>眩晕>
    --if self.aniState == Config.AnimationState.REPULSE and not breakAni then
    --    if aniState == Config.AnimationState.STUN then
    --        return ;
    --    end
    --end
    --
    --
    ----眩晕动作不被低优先级动作打断,主动动作可打断
    --if self.aniState == Config.AnimationState.STUN and not breakAni then
    --    --if aniState == Config.AnimationState.WALK or aniState == Config.AnimationState.RUN then
    --    --    return ;
    --    --elseif aniState == Config.AnimationState.ATTACK then
    --    --    return ;
    --    if aniState == Config.AnimationState.HIDE then
    --        return ;
    --    elseif aniState == Config.AnimationState.HURT then
    --        self.aniState = Config.AnimationState.IDLE;
    --    end
    --end

    self.aniStateNew = aniState;
    self.actionName = actionName;
    if onlyId ~= self.actionOnlyId then
        local onlyDamage = FightManager.getDamageAfterOtherOnlyId(self.actionOnlyId);
        if table.getn(onlyDamage) > 0 then
            for i, v in pairs(onlyDamage) do
                if v and type(v) == "table" then
                    --直接把没打完的伤害爆出来（基本是鞭尸
                    local damage = v.damage;
                    local damageType = v.damageType;
                    v.used = true;
                    local targetId = v.targetId;
                    for k, j in pairs(FightManager.fighterList) do
                        if targetId == j.fighterId then
                            --把该打在别人身上的伤害打出来
                            printError("(提示)前一状态伤害未结算完成", "OnlyId:" .. self.actionOnlyId, "frame:" .. v.frame, "skillId:" .. v.skillId, "damage:" .. v.damage);
                            j:damage(damageType, damage, true)
                        end
                    end
                end
            end
        end
    end
    self.actionOnlyId = onlyId or self.actionOnlyId;
    self.isLoop = isLoop;

    --切换一下攻击，为了连续播
    if aniState == Config.AnimationState.ATTACK then
        self.aniState = Config.AnimationState.IDLE;
    end

    if aniState == Config.AnimationState.IDLE or aniState == Config.AnimationState.HURT then
        --攻击加速结束 切换成正常速度
        if FightManager.entranceFinish then
            self.timeScale = FightManager.curTimeScale;
        end
    end
end

function Entity:getAniState()
    return self.aniState;
end

function Entity:getAnimationName(aniName)
    local modFile = self.model;
    --logMy("getAnimationName", modFile, aniName);
    if self.isFly then
        modFile = modFile.."-T";
    end
    local randomNames = GetStaticData("t_roleconfig", modFile, aniName);
    --local randomNames = string.split(str, ",");
    local animationName = nil;
    if randomNames then
        if type(randomNames) == "string" then
            animationName = randomNames;
        else
            animationName = randomNames[math.random(1, #randomNames)];
        end
    end

    --logMy('getAnimationName', aniName, modFile, str, randomNames, animationName);
    return animationName;
end

function Entity:setAttackShowType(type, value)
    if not self.isDead and not self.isDeading then
        if self.attackShowType ~= EnumConst.AttackShowType.NONE and type == EnumConst.AttackShowType.NONE then
            return ;
        end
        self.attackShowType = type;
        self.attackValue = value;
        if self.attackShowType == EnumConst.AttackShowType.MOVE then
            self.attackShowDuration = value.attackShowDuration;
            self.attackMoveSpeed = value.attackMoveSpeed;
            self.attackDirection = value.attackDirection;
        elseif self.attackShowType == EnumConst.AttackShowType.Back then
            self.attackShowDuration = value.attackShowDuration;
            self.attackMoveSpeed = value.attackMoveSpeed;
            self.attackDirection = value.attackDirection;
            --elseif self.attackShowType == EnumConst.AttackShowType.SPRINT then
        elseif self.attackShowType == EnumConst.AttackShowType.Protect or self.attackShowType == EnumConst.AttackShowType.SPRINT or self.attackShowType == EnumConst.AttackShowType.SPRINT_POS then
            self.attackMoveSpeed = value.attackMoveSpeed;
            self.attackDirection = value.attackDirection;
            self.attackMoveEnd = value.attackMoveEnd;
            self.attackMoveDelayTime = value.attackMoveDelayTime;
            if self.attackShowType == EnumConst.AttackShowType.SPRINT_POS then
                self.isRotation = true
            end
            self.targetPos = value.targetPos;
            self.attackDuration = value.attackDuration;
            --self.attackMoveSpecialEffect = value.attackMoveSpecialEffect;
        elseif self.attackShowType == EnumConst.AttackShowType.Flash then
        elseif self.attackShowType == EnumConst.AttackShowType.FullScreen then
            self.attackMoveEnd = value.attackMoveEnd;
            self.attackShowDuration = value.attackShowDuration;
        end
    end
end

function Entity:GetOrderInLayer()
    if self.roleObj ~= nil then
        local render = self.roleObj.transform:Find("Animation"):GetComponent("MeshRenderer")
        if render ~= nil then
            return render.sortingOrder
        end
    end
    return 0;
end

function Entity:setHitShowType(type, value)
    --logMy('setHitShowType', self.fighterId, type, value);

    if not self.isDead and not self.isDeading then
        self.hitShowType = type;
        self.hitValue = value;
        if self.hitShowType == EnumConst.HitShowType.REPULSE or self.hitShowType == EnumConst.HitShowType.PULL then

            self.hitShowDuration = value.hitShowDuration;
            self.maxHitShowDuration = self.hitShowDuration;
            self.hitMoveSpeed = value.hitMoveSpeed;
            self.hitDirection = value.hitDirection;
        elseif self.hitShowType == EnumConst.HitShowType.HITDOWN then
            self.hitFlyTime = -1;
        elseif self.hitShowType == EnumConst.HitShowType.HIDE then
            self.hitShowDuration = value.hideTime;
            self.maxHitShowDuration = self.hitShowDuration;
            self.maxHideTime = value.hideTime;
            self.hideTransitionTime = 0.5;--value.hideTime/10;
            --self.roleObj:SetActive(false);
            if not Util.IsNull(self.skeletonAnimation) and not Util.IsNull(self.shadow.skeletonAnimation) then
                self.skeletonAnimation.Skeleton.A = 0;
                self.shadow.skeletonAnimation.Skeleton.A = 0;
            end

            self.hideHeadBar = self.hitValue.hideHeadBar
            if self.headBar and self.hideHeadBar == 1 then
                self:setHeadBar(false, false)
            end
            for k, v in pairs(self.buffEffect) do
                for i, j in pairs(v) do
                    if not Util.IsNull(j.skeletonAnimation) then
                        j.skeletonAnimation.Skeleton.A = 0
                    elseif not self.isEmpty then
                        local str = j.roleObj and j.roleObj.name or "";
                        --printError("Skeleton有问题", "name = " .. str);

                    end
                end
            end
        elseif self.hitShowType == EnumConst.HitShowType.STUN then

        end
        --击飞单独处理，击飞时可以击退，可以禁锢，防止击飞被打断
        if type == EnumConst.HitShowType.HITFLY then
            if self.hitShowTypeHitFly ~= EnumConst.HitShowType.HITFLY then
                self.hitShowDurationHitFly = value.hitShowDuration;
                self.hitShowTime = self.hitShowDurationHitFly;
                --正在飞时，不能重置原位置 不能重置击飞时间

                self.hitShowOriginalPosition = self:getPosition();
                print("击飞初始点", self.hitShowOriginalPosition.x, self.hitShowOriginalPosition.z);
                self.duration = self.hitShowDurationHitFly;
                self.hitShowTypeHitFly = type;
            end

        end
    end
end

function Entity:showSpecialAnimation()
    for k, v in pairs(self.buffs) do
        if v.buffBean.f_BuffPerformance == EnumConst.Buff_PerformanceType.STUN then
            if self.isDead == false and self.aniState ~= FighterAnimationState.STUN then
                self.playStun();
                break ;
            end
        elseif v.buffBean.f_BuffPerformance == EnumConst.Buff_PerformanceType.FREZE then
            if self.isDead == false and self.aniState ~= FighterAnimationState.FREEZY then
                self.roleObj.transform:Find("Animation"):GetComponent("Role"):PauseCurrentAction();
                self.aniState = Config.AnimationState.FREEZY;
                break ;
            end
        end
    end
end

function Entity:showHitFly(time, velocity, acceleration)
    self.hitFlyTime = time / 1000;
    self.velocity = velocity / EnumConst.TEN_THOUSANDTH;
    self.acceleration = acceleration / EnumConst.TEN_THOUSANDTH;
    self.hitFlyDuration = self.hitFlyTime;
    self:setAniState(Config.AnimationState.HITFLY);
end

function Entity:showRepulse(time, velocity, targetPos)
    self.repulseTime = time / EnumConst.THOUSANDTH;
    self.repulseVelocity = velocity / EnumConst.TEN_THOUSANDTH;
    self.repulsePos = targetPos;
    self.repulseDuration = self.repulseTime;
    --self:setAniState(Config.AnimationState.REPULSE);
end

function Entity:PauseCurrentAction()
    if (not self.isEmpty) then
        Util.PauseCurrentAction(self.roleObj.transform:Find("Animation").gameObject);
        Util.PauseCurrentAction(self.shadow.skeletonAnimation.gameObject);

    end
end

function Entity:ResumeCurrentAction()
    if (not self.isEmpty) then
        Util.ResumeCurrentAction(self.roleObj.transform:Find("Animation").gameObject, self.timeScale);
        Util.ResumeCurrentAction(self.shadow.skeletonAnimation.gameObject, self.timeScale);

    end
end

function Entity:addSkillEffect(type, effect)
    if self.skillEffect[type] == nil then
        self.skillEffect[type] = {}
    end
    --printError("id, skillid", effect.fighterId, effect.skillId)
    table.insert(self.skillEffect[type], effect);
end

function Entity:setSkillEffectFlip(type, flip)
    if self.skillEffect[type] then
        for _, effect in pairs(self.skillEffect[type]) do
            if effect then
                effect:setFlip(flip);
            end
        end
    end
end
--切换速度时修改角色特效速度
function Entity:setSkillEffectTimeScale()
    for k, list in pairs(self.skillEffect) do
        for _, effect in pairs(list) do
            if effect then
                effect:setTimeScale();
            end
        end
    end

    for k, v in pairs(self.buffEffect) do
        if v then
            if v[buffFrontKey] then
                v[buffFrontKey]:setTimeScale();
            end
            if v[buffBackKey] then
                v[buffBackKey]:setTimeScale();
            end
        end
    end
end

function Entity:getSkillEffect(skillId)
    for k, list in pairs(self.skillEffect) do
        for _, effect in pairs(list) do
            if effect.skillId == skillId then
                return effect;
            end
        end
    end
end
--获取当前正在释放的技能
function Entity:getCurSkillEffect()
    local playingSkill = {};
    for k, list in pairs(self.skillEffect) do
        if k == EnumConst.EntitySkillEffectType.SKILLF or k == EnumConst.EntitySkillEffectType.SKILLB then
            for _, effect in pairs(list) do
                if effect.duration and effect.duration > 0 then
                    table.insert(playingSkill, effect);
                end
            end
        end
    end
    return playingSkill;
end

function Entity:removeSkillEffect(skillId)
    for k, list in pairs(self.skillEffect) do
        for i, effect in pairs(list) do
            if effect.skillId == skillId then
                table.remove(self.skillEffect, i);
            end
        end
    end
end

function Entity:PauseEffect()

    for k, list in pairs(self.skillEffect) do
        for _, effect in pairs(list) do
            if effect then
                if k == EnumConst.EntitySkillEffectType.HITF or k == EnumConst.EntitySkillEffectType.HITB then
                else
                    effect:pause();
                end
            end
        end
    end

    for k, v in pairs(self.buffEffect) do
        if v then
            if v[buffFrontKey] then
                v[buffFrontKey]:pause();
            end
            if v[buffBackKey] then
                v[buffBackKey]:pause();
            end
        end
    end

    --if self.skillFObj then
    --    self.skillFObj:pause();
    --end
    --
    --if self.skillFObj1 then
    --    self.skillFObj1:pause();
    --end
    --
    --if self.skillBObj then
    --    self.skillBObj:pause();
    --end
    --
    --if self.hitFObj then
    --    self.hitFObj:pause();
    --end
    --
    --if self.hitBObj then
    --    self.hitBObj:pause();
    --end
    --
    --if self.bulletFObj then
    --    self.bulletFObj:pause();
    --end
    --
    --if self.bulletBObj then
    --    self.bulletBObj:pause();
    --end

end

function Entity:ResumeEffect()

    for k, list in pairs(self.skillEffect) do
        for _, effect in pairs(list) do
            if effect then
                effect:play();
            end
        end
    end

    for k, v in pairs(self.buffEffect) do
        if v then
            if v[buffFrontKey] then
                v[buffFrontKey]:play();
            end
            if v[buffBackKey] then
                v[buffBackKey]:play();
            end
        end
    end

    --if self.skillFObj then
    --    self.skillFObj:play();
    --end
    --
    --if self.skillFObj1 then
    --    self.skillFObj1:play();
    --end
    --
    --if self.skillBObj then
    --    self.skillBObj:play();
    --end
    --
    --if self.hitFObj then
    --    self.hitFObj:play();
    --end
    --
    --if self.hitBObj then
    --    self.hitBObj:play();
    --end
    --
    --if self.bulletFObj then
    --    self.bulletFObj:play();
    --end
    --
    --if self.bulletBObj then
    --    self.bulletBObj:play();
    --end

end

function Entity:RemoveAllEffect()

    for k, list in pairs(self.skillEffect) do
        for _, effect in pairs(list) do
            if effect then
                local skillInfo = G.dataTable["t_skill"][tostring(effect.skillId)]
                if skillInfo and skillInfo.f_dieContinue then
                else
                    effect:stop();
                end

            end
        end
    end

    self.skillEffect = {}

    self:RemoveAllBuff();

    ----缺陷，类似skillFObj，会被后面设定的代替掉，如果在pause的时候被暂停了，结果就不会自己把自己删掉了，也没有引用的ref了
    --if self.skillFObj then
    --    self.skillFObj:stop();
    --    self.skillFObj = nil;
    --end
    --
    --if self.skillFObj1 then
    --    self.skillFObj1:stop();
    --    self.skillFObj1 = nil;
    --end
    --
    --if self.skillBObj then
    --    self.skillBObj:stop();
    --    self.skillBObj = nil;
    --end
    --
    --if self.hitFObj then
    --    self.hitFObj:stop();
    --    self.hitFObj = nil;
    --end
    --
    --if self.hitBObj then
    --    self.hitBObj:stop();
    --    self.hitBObj = nil;
    --end
    --
    --if self.bulletFObj then
    --    self.bulletFObj:stop();
    --    self.bulletFObj = nil;
    --end
    --
    --if self.bulletBObj then
    --    self.bulletBObj:stop();
    --    self.bulletBObj = nil;
    --end
end

--死亡时，停止施法特效
function Entity:RemoveSkillEffect()
    for type, list in pairs(self.skillEffect) do
        for index, effect in pairs(list) do
            if effect then
                table.insert(FightManager.effectTempCacheList, effect);
            end
            --printError(self.fighterId, effect.name, type)
            if (type ~= EnumConst.EntitySkillEffectType.HITF and type ~= EnumConst.EntitySkillEffectType.HITB) and effect then
                local cfg = G.dataTable["t_skillshow"][tostring(effect.skillId)];
                if cfg and toNumber(cfg.f_SkillShowType) == EnumConst.AttackShowType.TARGETEFFECT then
                    --暂时不停止，直至播完，如果这个类型的特效是循环播放的话（现在没有），人死后还会继续放
                    --table.insert(FightManager.effectTempCacheList, effect);
                else
                    effect:stop(true, true);
                    --self.skillEffect[type] = nil;
                end
            else
                effect:stop();
            end
            self.skillEffect[type] = nil;
        end
    end
end

--播放施法动作
function Entity:playSkillAction(skillShow, attackSpeed, skillOnlyId)
    local actionName = Entity:GetTableValue(skillShow, "f_AnimResource");
    local loop = Entity:GetTableValue(skillShow, "f_AnimLoop");
    if loop == nil then
        loop = 0;
    end
    if attackSpeed then
        --if self.fighterId == 1 then
        --    self.attackSpeed = 0.5;
        --end
        self.attackSpeed = attackSpeed;

    else
        self.attackSpeed = 1;
    end
    if actionName ~= nil and actionName ~= "" then
        if tonumber(loop) > 0 then
            self:setAniState(Config.AnimationState.ATTACK, actionName, true, true, skillOnlyId);
        else
            self:setAniState(Config.AnimationState.ATTACK, actionName, false, true, skillOnlyId);
        end
    end
end

--特效接口
function Entity:playEffectResV2(param, type)
    --if param.effectRes == 'b025' then
    --    logMy('playEffectResV2, ', self.fighterId, param);
    --end

    if param.effectRes ~= nil and param.effectRes ~= "" then
        if self then
            param:setFighterId(self.fighterId);
            if not type then
                param:setTimeScale(self.timeScale)
            else
                param:setTimeScale(1)
            end
        end
        -- SpineEffect:newV2(param);--
        local eff = SpineEffect.Get(param)
        eff:init()
        --- 不要因为bug就把缓存去掉，应该找到bug修正
        --此处会造成一些特效残留在场景里，应该是和对象池共同使用，没处理好造成的。未定位到精确位置，暂时注释。
        --比较明显的b013特效，会有其他的，比较明显的是战斗结束后，特效和技能对象没有SetActive false，
        --eff:setFunc(function()
        --    self:ReStoreSpineEffect(eff)
        --end)
        eff:startDelay()
        return eff;
    end
    return nil;
end

--施法特效
function Entity:playSkill(mySelf, skillShow, flip, scale, other, isNotMove, skillFixedPos, isLink)
    if skillShow.f_CameraShock and skillShow.f_CameraShock ~= "" then
        if not HelperFunc.IsNull(mySelf) then
            mySelf:ShakeCamera(1, skillShow.f_CameraShock[1]);
        end

    end
    if skillShow.f_SkillID == 454402 then
        local a = 1;
    end
    local effectFResList = Entity:GetTableValue(skillShow, "f_SkillFResource");
    --local effectFResList = string.split(effectFResRaw, ",");
    local effectFRes = effectFResList[1];
    local skillShowType = Entity:GetTableValue(skillShow, "f_SkillShowType")
    local actionFName = Entity:GetTableValue(skillShow, "f_SkillFName");
    local animLoop = Entity:GetTableValue(skillShow, "f_AnimLoop");
    local skinId = FightManager.skinId2Fighter[self.fighterId];
    if SkillManager.checkSkillSkin(skillShow.f_SkillID) then
        skinId = nil;
    end
    --if effectFRes == 'fxh016f' and actionFName == 'skill1' then
    --    logMy('playSkill, flip', flip, effectFRes);
    --end

    --勾人技能表现，--133101,勾子表现，暂时处理，特效和配置表就位后修改。特效需要两端有锚点
    --local hookEffect = false;
    --if skillShow.f_SkillID == 133101 then
    --    hookEffect = true;
    --end
    local effFObj = nil;
    if effectFRes ~= nil and actionFName ~= "" then
        if skinId then
            effectFRes = effectFRes .. "-" .. skinId;
        end
        local positionDesc = Entity:GetTableValue(skillShow, "f_SkillFPosition");
        local OtherPositionDesc = Entity:GetTableValue(skillShow, "f_HitFPosition");
        local param = SpineEffectParam.Get(effectFRes, Config.SortingDefault.Role, flip, actionFName, skillShow.f_SkillID);
        param:setRenderDeepZ(Entity:GetTableValue(skillShow, "f_AxisDeviation1"))
        param:setSpineType(EnumConst.SpineEffectType.SKILL);
        param.skillShowType = skillShowType
        --param:setFollow(mySelf:getFollowTrans(positionDesc));
        if isNotMove and skillShow.f_SkillShowType == 3 then
            local fixedPos = skillFixedPos ~= nil and skillFixedPos or mySelf:getFollowBone(positionDesc).position;
            --local pos =mySelf:getFollowBone(positionDesc).position ;--mySelf:getFollowBone(positionDesc).position;
            fixedPos = fixedPos or Vector3(0, 0, 0)
            local pos = Vector3(fixedPos.x, 300, fixedPos.y);
            param:setPosition(pos);
        else
            if isLink then
                --艾可抓人
                param:setFollow(other:getFollowBone(positionDesc));
                param:setHookFollow(mySelf:getFollowBone(OtherPositionDesc));
                param:setFighterId(mySelf.fighterId);
                --param:setLinkFollow(other:getFollowBone(positionDesc))

            else
                param:setFollow(mySelf:getFollowBone(positionDesc));
                param:setFighterId(mySelf.fighterId);
            end

            param.scale = scale or param.scale;
            local bossCfg = logicMgr.TrialsManager.GetBossConfigById(self.partnerModelId);
            if bossCfg ~= nil or GuildManager.checkIsGuildBossByModelId(self.partnerModelId) or FightManager.checkSoloBoss(self.partnerModelId) then
                param.scale = param.scale * FightManager.bossScale;
            end
            local skillDuration = Entity:GetLoopSkillDuration(skillShow);
            if animLoop == 1 then
                param:setLoop(true);
                --duration为负时，是技能做循环表现，为了和buff区分开
            end
        end

        --if hookEffect then
        --
        --    param:setSpeed(1);
        --    param:setFollow(other:getFollowBone(positionDesc));
        --    param:setHookFollow(mySelf:getFollowBone(positionDesc));
        --    param:setLoop(true);
        --    param:setDuration(-2);
        --    local flip = getRoleFlip(other, mySelf);
        --
        --    if other and other.roleObj and mySelf and mySelf.roleObj then
        --        local flyStartPos = other.roleObj.transform.position;-- self:getOffsetPosition(skillShow.f_FlyFPosition, flip);
        --        local hitPos = mySelf.roleObj.transform.position;--mySelf:getOffsetPosition(skillShow.f_HitFPosition, flip);
        --
        --        local flyDir = hitPos - flyStartPos;
        --        local speed = 0;--Vector3.Normalize(flyDir);
        --        local distance = flyDir.magnitude;
        --        printError("distance", distance);
        --        --speed = speed * (distance/2);
        --        param:setSpeed(speed);
        --    end
        --
        --end
        param:setCaster(mySelf);
        if isLink then
            param:setCaster(other);

        end
        effFObj = mySelf:playEffectResV2(param);
        --mySelf.skillFObj = effFObj;
        if not isNotMove then
        end
        if isLink then
            other:addSkillEffect(EnumConst.EntitySkillEffectType.SKILLF, effFObj);
        else
            mySelf:addSkillEffect(EnumConst.EntitySkillEffectType.SKILLF, effFObj);
        end

    end

    --
    if #effectFResList > 1 then
        effectFRes = effectFResList[2];
        --logMy('effectFResList[2]', effectFResList);

        if effectFRes ~= nil and actionFName ~= "" then
            if skinId then
                effectFRes = effectFRes .. "-" .. skinId;
            end
            local positionDesc = Entity:GetTableValue(skillShow, "f_SkillFPosition");
            local param = SpineEffectParam.Get(effectFRes, Config.SortingDefault.Role, flip, actionFName, skillShow.f_SkillID);
            --param:setFollow(mySelf:getFollowTrans(positionDesc));
            param:setSpineType(EnumConst.SpineEffectType.SKILL);
            param:setRenderDeepZ(Entity:GetTableValue(skillShow, "f_AxisDeviation2"))
            param.skillShowType = skillShowType
            if isNotMove and skillShow.f_SkillShowType == 3 then
                local fixedPos = skillFixedPos ~= nil and skillFixedPos or mySelf:getFollowBone(positionDesc).position;
                --local pos =mySelf:getFollowBone(positionDesc).position ;--mySelf:getFollowBone(positionDesc).position;
                local posChangeX = tonumber(positionDesc[1]) * (flip and -1 or 1);
                local posChangeZ = tonumber(positionDesc[2])
                fixedPos = fixedPos or Vector3(0, 0, 0)
                local pos = Vector3(fixedPos.x + posChangeX, 300, fixedPos.y + posChangeZ);
                param:setPosition(pos);
            else
                param:setFollow(mySelf:getFollowBone(positionDesc));
                param:setFighterId(mySelf.fighterId);
                local skillDuration = Entity:GetLoopSkillDuration(skillShow);
                if animLoop == 1 then
                    param:setLoop(true);
                    --duration为负时，是技能做循环表现，为了和buff区分开
                    --param:setDuration(-1);
                end
            end
            param:setCaster(mySelf);
            effFObj = mySelf:playEffectResV2(param);

            if not isNotMove then
                --mySelf.skillFObj1 = effFObj;
            end
            mySelf:addSkillEffect(EnumConst.EntitySkillEffectType.SKILLF, effFObj);
        end
    end

    local effectBRes = Entity:GetTableValue(skillShow, "f_SkillBResource");
    local actionBName = Entity:GetTableValue(skillShow, "f_SkillBName");
    local effBObj = nil;
    if effectBRes ~= nil and actionBName ~= "" then
        local positionDesc = Entity:GetTableValue(skillShow, "f_SkillBPosition");
        if skinId then
            effectFRes = effectFRes .. "-" .. skinId;
        end
        local param = SpineEffectParam.Get(effectBRes, Config.SortingDefault.Back_Effect, flip, actionBName, skillShow.f_SkillID);
        --param:setFollow(mySelf:getFollowTrans(positionDesc));
        param:setRenderDeepZ(Entity:GetTableValue(skillShow, "f_AxisDeviation3"))
        param:setSpineType(EnumConst.SpineEffectType.SKILL);
        param.skillShowType = skillShowType
        if isNotMove and skillShow.f_SkillShowType == 3 then
            local fixedPos = skillFixedPos ~= nil and skillFixedPos or mySelf:getFollowBone(positionDesc).position;
            --local pos = skillFixedPos;-- mySelf:getFollowBone(positionDesc).position;
            fixedPos = fixedPos or Vector3(0, 0, 0)
            local pos = Vector3(fixedPos.x, 300, fixedPos.y);
            param:setPosition(pos);
        else
            param:setFollow(mySelf:getFollowBone(positionDesc));
            param:setFighterId(mySelf.fighterId);
            local skillDuration = Entity:GetLoopSkillDuration(skillShow);
            if animLoop == 1 then
                param:setLoop(true);
                --duration为负时，是技能做循环表现，为了和buff区分开
                --param:setDuration(-1);
            end
        end
        param:setCaster(mySelf);
        effBObj = mySelf:playEffectResV2(param);
        --mySelf.skillBObj = effBObj;
        if not isNotMove then
        end
        mySelf:addSkillEffect(EnumConst.EntitySkillEffectType.SKILLB, effBObj);
    end

    --test 水波纹效果
    local effect = skillShow.f_Ripple;
    if effect and effect ~= "" then
        if effect[1] == 1 or effect[1] == 3 then
            self:PlayDistortionEffect(skillShow);
        elseif effect[1] == 2 then
            mySelf:PlayDistortionEffect(skillShow);
        end
    end
    --EffectUtil.ShowDistortion(mySelf:getWorldPosition());

    return effFObj, effBObj;
end

function Entity:PlayDistortionEffect(skillShow)

    local effect = skillShow.f_Ripple
    local type = effect[1]; --1施法者，2目标，3地图（读取特效坐标）
    local positionDesc = clone(effect[2]);
    table.insert(positionDesc, ",foot_drop");--写死绑点
    local delay = effect[3] * 0.001 / FightManager.curTimeScale;

    local param = {}--参数
    param.f_waveCount = effect[4];
    param.f_waveTotalTime = effect[5];
    param.f_maxInRadius = effect[6];
    param.f_radius = effect[7];
    --默认施法者
    local followInfo = EffectFunctions.getFollowInfo(self:getFollowBone({ 0, 0 }));
    if type then
        if type == 1 then
            followInfo = EffectFunctions.getFollowInfo(self:getFollowBone(positionDesc));

        elseif type == 2 then
            positionDesc = Entity:GetTableValue(skillShow, "f_HitFPosition");
            followInfo = EffectFunctions.getFollowInfo(self:getFollowBone(positionDesc));
        elseif type == 3 then
            local pos = Entity:GetTableValue(skillShow, "f_CenterFPosition")
            followInfo.fullPosition = Vector3(0, 0, 0);
            followInfo.fullPosition.x = tonumber(pos[1]) + effect[2][1];
            followInfo.fullPosition.y = 300;
            followInfo.fullPosition.z = tonumber(pos[2]) + effect[2][2];

        end

        --calc effect center position
        followInfo.rotatedOffset = EffectFunctions.rotateOffset(followInfo.offset, self.flip, followInfo.rotatedOffset);

        --if delay > 0.01 then -- > 0
        --    Util.WaitForSeconds(function ()
        --        Entity.DoPlayDistortionEffect(followInfo);
        --
        --    end, delay);
        --else
        --    Entity.DoPlayDistortionEffect(followInfo);
        --end

        self.distortionEffect = { followInfo = followInfo, delayTime = delay, time = 0, effectInfo = param };
    end

    --EffectFunctions.calcFollowPositionV2(followInfo);
    --if followInfo.position then
    --    --logMy('PlayDistortionEffect', followInfo.position.x, followInfo.position.y);
    --    --EffectUtil.ShowDistortion(followInfo.position.x, followInfo.position.y);
    --
    --    --logMy('PlayDistortionEffect', followInfo.position);
    --    EffectUtil.ShowDistortion(followInfo.position);
    --end

end

function Entity.DoPlayDistortionEffect(followInfo, effectInfo)

    EffectFunctions.calcFollowPositionV2(followInfo);
    if followInfo.fullPosition then
        EffectUtil.ShowDistortion(followInfo.fullPosition, effectInfo.f_waveCount, effectInfo.f_waveTotalTime, effectInfo.f_maxInRadius, effectInfo.f_radius);
    elseif followInfo.position then
        --logMy('PlayDistortionEffect', followInfo.position.x, followInfo.position.y);
        --EffectUtil.ShowDistortion(followInfo.position.x, followInfo.position.y);

        --logMy('PlayDistortionEffect', followInfo.position);
        EffectUtil.ShowDistortion(followInfo.position, effectInfo.f_waveCount, effectInfo.f_waveTotalTime, effectInfo.f_maxInRadius, effectInfo.f_radius);
        --EffectUtil.ShowDistortion(followInfo.position);
    end
end

function Entity:GetLoopSkillDuration(skillShow)
    local nextSkillDelay = 0;
    if skillShow.f_NextSkill ~= nil and skillShow.f_NextSkill ~= "" then
        local nextSkills = skillShow.f_NextSkill--decodeJsonStrToTabel(skillShow.f_NextSkill);
        if nextSkills ~= nil and #nextSkills > 0 then
            nextSkillDelay = nextSkills[1][2];
            nextSkillDelay = nextSkillDelay / EnumConst.THOUSANDTH;
        end
    end
    return nextSkillDelay;
end
--场景特效
function Entity:playCenter(mySelf, skillShow)
    local effectFRes = Entity:GetTableValue(skillShow, "f_CenterFResource");
    local actionFName = Entity:GetTableValue(skillShow, "f_CenterFName");
    local effFObj = nil;
    local skinId = FightManager.skinId2Fighter[self.fighterId];
    if effectFRes ~= nil and actionFName ~= "" then
        if skinId then
            effectFRes = effectFRes .. "-" .. skinId;
        end
        local offset = Entity:GetTableValue(skillShow, "f_CenterFPosition");
        --local offset = string.split(offsetPos, ",");
        local pos = Vector3(offset[1], 300, offset[2]);
        --offsetPos = "0,0";
        --effFObj = Entity:playEffectRes(effectFRes,actionFName,Config.SortingDefault.Front_Effect,pos,offsetPos,nil,mySelf.flip,nil,false,false,nil,false);

        local param = SpineEffectParam.Get(effectFRes, Config.SortingDefault.Front_Effect, mySelf.flip, actionFName, skillShow.f_SkillID);
        param:setPosition(pos);
        param:setSpineType(EnumConst.SpineEffectType.SKILL);
        param:setCaster(mySelf);
        effFObj = mySelf:playEffectResV2(param);
        mySelf:addSkillEffect(EnumConst.EntitySkillEffectType.SKILLF, effFObj);
    end
    local effectBRes = Entity:GetTableValue(skillShow, "f_CenterBResource");
    local actionBName = Entity:GetTableValue(skillShow, "f_CenterBName");
    local effBObj = nil;
    if effectBRes ~= nil and actionBName ~= "" then
        local offset = Entity:GetTableValue(skillShow, "f_CenterBPosition");
        --local offset = string.split(offsetPos, ",");
        local pos = Vector3(offset[1], 300, offset[2]);
        --offsetPos = "0,0";
        --effBObj = Entity:playEffectRes(effectBRes,actionBName,Config.SortingDefault.Back_Effect,pos,offsetPos,nil,mySelf.flip,nil,false,false,nil,false);

        if skinId then
            effectFRes = effectFRes .. "-" .. skinId;
        end
        local param = SpineEffectParam.Get(effectBRes, Config.SortingDefault.Back_Effect, mySelf.flip, actionBName, skillShow.f_SkillID);
        param:setPosition(pos);
        param:setSpineType(EnumConst.SpineEffectType.SKILL);
        param:setCaster(mySelf);
        effBObj = mySelf:playEffectResV2(param);
        mySelf:addSkillEffect(EnumConst.EntitySkillEffectType.SKILLB, effBObj);
    end

    return effFObj, effBObj;
end

--受击特效
function Entity:playHit(mySelf, skillShow, flip)

    --Util.Log('doHitColor')
    --if mySelf.isDead then
    --    return;
    --end
    mySelf:doHitColor()
    Entity:playHitAudio(mySelf, skillShow);

    local effectFRes = Entity:GetTableValue(skillShow, "f_HitFResource");
    local actionFName = Entity:GetTableValue(skillShow, "f_HitFName");

    --if effectFRes == 'fxh016o' then
    --    logMy('playHit effect flip', flip, effectFRes);
    --end

    local effFObj = nil;
    local skinId = FightManager.skinId2Fighter[self.fighterId];
    if effectFRes ~= nil and actionFName ~= "" then
        if SkillManager.checkHitSkin(effectFRes) then
            skinId = nil;
        end
        if skinId then
            effectFRes = effectFRes .. "-" .. skinId;
        end
        local offsetPos = Entity:GetTableValue(skillShow, "f_HitFPosition");

        local param = SpineEffectParam.Get(effectFRes, Config.SortingDefault.Role, flip, actionFName, skillShow.f_SkillID);
        --param:setFollow(mySelf:getFollowTrans(offsetPos));
        param:setSpineType(EnumConst.SpineEffectType.HIT);
        param:setFollow(mySelf:getFollowBone(offsetPos));
        param:setCaster(mySelf);
        effFObj = mySelf:playEffectResV2(param, EnumConst.FightActionType.HIT);
        --mySelf.hitFObj = effFObj;
        mySelf:addSkillEffect(EnumConst.EntitySkillEffectType.HITF, effFObj);
    end
    local effectBRes = Entity:GetTableValue(skillShow, "f_HitBResource");
    local actionBName = Entity:GetTableValue(skillShow, "f_HitBName");
    local effBObj = nil;
    if effectBRes ~= nil and actionBName ~= "" then
        if SkillManager.checkHitSkin(effectBRes) then
            skinId = nil;
        end
        if skinId then
            effectBRes = effectBRes .. "-" .. skinId;
        end
        local offsetPos = Entity:GetTableValue(skillShow, "f_HitBPosition");

        local param = SpineEffectParam.Get(effectBRes, Config.SortingDefault.Back_Effect, flip, actionBName, skillShow.f_SkillID);
        --param:setFollow(mySelf:getFollowTrans(offsetPos));
        param:setSpineType(EnumConst.SpineEffectType.HIT);
        param:setFollow(mySelf:getFollowBone(offsetPos));
        param:setCaster(mySelf);

        effBObj = mySelf:playEffectResV2(param, EnumConst.FightActionType.HIT);
        --mySelf.hitBObj = effBObj;
        mySelf:addSkillEffect(EnumConst.EntitySkillEffectType.HITB, effBObj);

    end
    return effFObj, effBObj;
end

--受击变色
function Entity:doHitColor()

    --logMy('doHitColor', self.fighterId);

    if self.entityEffect then
        self.entityEffect:startFlashEffect();
    end
end

--飞行特效
function Entity:playFly(mySelf, target, skillShow, speed, duration, pos, func, flip, realFighter, skillFixedPos)
    --logMy('Entity:playFly', mySelf.fighterId,skillShow,speed,duration,pos)
    if flip == nil then
        flip = mySelf.flip;
    end
    local effectFRes = Entity:GetTableValue(skillShow, "f_FlyFResource");
    local actionFName = Entity:GetTableValue(skillShow, "f_FlyFName");
    local flyHold = Entity:GetTableValue(skillShow, "f_FlyHold") == 1;
    local skillId = skillShow.f_SkillID;
    local showType = skillShow.f_SkillShowType;
    local skillIData = G.dataTable["t_skill"][tostring(skillId)];
    local effFObj = nil;
    local skinId = FightManager.skinId2Fighter[mySelf.fighterId];
    if realFighter then
        skinId = FightManager.skinId2Fighter[realFighter];
    end
    if effectFRes ~= nil and actionFName ~= "" then
        if SkillManager.checkBulletSkin(effectFRes) then
            skinId = nil;
        end
        local offsetPos = Entity:GetTableValue(skillShow, "f_FlyFPosition");
        local vPos = Vector3(pos.x, pos.y, pos.z);
        --effFObj = Entity:playEffectRes(effectFRes,actionFName,Config.SortingDefault.Front_Effect,vPos,offsetPos,duration,mySelf.flip,speed,false,false,nil,flyHold);
        if skinId then
            effectFRes = effectFRes .. "-" .. skinId;
        end
        --todo effect
        local param = SpineEffectParam.Get(effectFRes, Config.SortingDefault.Role, flip, actionFName, skillId);
        param:setDuration(duration);
        param:setSpineType(EnumConst.SpineEffectType.BULLET);
        param:setSpeed(speed);
        --param:setFlyHold(flyHold, vPos, mySelf:getFollowTrans(offsetPos));
        param:setFly(vPos, speed, flyHold);
        param:setCaster(mySelf);
        param:setSuffer(target);

        if skillIData then
            if (skillIData.f_SkillOver == 3 and skillIData.f_SkillOut == 1) then
                param:setTargetPos(skillFixedPos);
            end
        end
        if showType == EnumConst.AttackShowType.flyPosition or showType == EnumConst.AttackShowType.flyPositionBack then
            param:setTargetPos(Vector3.New(skillFixedPos.x, skillFixedPos.z, skillFixedPos.z));

        end
        effFObj = mySelf:playEffectResV2(param);
        --mySelf.bulletFObj = effFObj;
        mySelf:addSkillEffect(EnumConst.EntitySkillEffectType.BULLETF, effFObj);

        if effFObj ~= nil then
            if obj then
                effFObj.skillClass = obj;
                table.insert(obj.SpineEffects, effFObj)
            end
            effFObj:setFunc(func);
        end
    end
    local effectBRes = Entity:GetTableValue(skillShow, "f_FlyBResource");
    local actionBName = Entity:GetTableValue(skillShow, "f_FlyBName");
    local effBObj = nil;
    if effectBRes ~= nil and actionBName ~= "" then
        local offsetPos = Entity:GetTableValue(skillShow, "f_FlyBPosition");
        local vPos = Vector3(pos.x, pos.y, pos.z);
        --effBObj = Entity:playEffectRes(effectBRes,actionBName,Config.SortingDefault.Back_Effect,vPos,offsetPos,duration,mySelf.flip,speed,false,false,nil,flyHold);
        if skinId then
            effectFRes = effectFRes .. "-" .. skinId;
        end
        --todo effect
        local param = SpineEffectParam.Get(effectBRes, Config.SortingDefault.Back_Effect, flip, actionBName, skillId);
        param:setDuration(duration);
        param:setSpineType(EnumConst.SpineEffectType.BULLET);
        param:setSpeed(speed);
        --param:setFlyHold(flyHold, vPos, mySelf:getFollowTrans(offsetPos));
        param:setFly(vPos, speed, flyHold);
        param:setCaster(mySelf);
        param:setSuffer(target);
        if skillIData then
            if skillIData.f_SkillOver == 3 and skillIData.f_SkillOut == 1 or showType == EnumConst.AttackShowType.flyPosition then
                param:setTargetPos(skillFixedPos);
            end
        end
        effBObj = mySelf:playEffectResV2(param);
        --mySelf.bulletBObj = effBObj;
        mySelf:addSkillEffect(EnumConst.EntitySkillEffectType.BULLETB, effBObj);
        if obj then
            effBObj.skillClass = obj;
            table.insert(obj.SpineEffects, effBObj)
        end
    end
    return effFObj, effBObj;
end

--添加buff
function Entity:AddBuff(buffData, buffShow, caster, buffServerId)
    if buffData.f_BuffEffect ~= nil and buffData.f_BuffEffect ~= "" then
        if buffData.f_BuffEffect == 48 then
            self.isMask = true;
        end
    end
    if buffData.f_Tag ~= nil and buffData.f_Tag ~= "" then
        for i, v in pairs(buffData.f_Tag) do
            if v == 1014 then
                --不飘字buff
                self.isShowDamage = false;
            end
            if v == 1015 then
                --拉取状态标记
                self.isHook = true;
            end
            if v == 1101 then
                --石化
                self.isPetrifaction = true;
                EffectUtil.SetObjPetrifaction(self.roleObj, 1)
                self:setAniState(Config.AnimationState.PETRIFACTION, nil, true, true);
            end
            if v == 1 then
                --霸体标记
                self.isSuperArmor = true;
            end
            if v == 1027 then

                local playingSkill = self:getCurSkillEffect();
                for _, skilling in pairs(playingSkill) do
                    skilling:stop();
                end
            end
            if v == 1031 then
                --大招进入飞行状态并清空连射
                self.isFly = true;
            end

            end
    end

    if buffShow and buffShow.f_BuffVEXResource == "b132" and caster.partnerModelId == "610" then
        local flip = false;
        local target = FightManager.getEntityByModel("611", self.teamIndex);
        if target ~= nil then
            flip = getRoleFlip(self, target);
            self:setFlip(flip);
        end
    end
    self:AddBuffShow(buffData, buffShow, caster, buffServerId, true);
    self:AddBuffShow(buffData, buffShow, caster, buffServerId, false);
end

function Entity:AddBuffShow(buffData, buffShow, caster, buffServerId, front)

    --logMy('Entity:AddBuff', buffShow);

    --互斥buff标记 应该在服务器处理，这儿不处理了，看了excel表，貌似也没有在用
    --同一个buffId的buff能同时在身上存在，所以第二段也注释掉了

    local VEXResource = nil;
    if front then
        VEXResource = buffShow.f_BuffVEXResource;
    else
        VEXResource = buffShow.b_BuffVEXResource;
    end

    --特效
    --log("=====================Entity:AddBuff"..buffShow.f_BuffId);
    if buffShow ~= nil and VEXResource ~= nil and VEXResource ~= "" then
        --log("=====================Entity:AddBuff1");
        local buffId = buffShow.f_BuffId;
        local effectRes = nil;
        local beginName = nil;
        local loopName = nil;
        local offsetPosTemp = nil;
        local offsetPos_caster = nil;
        local duration = nil;
        if front then
            effectRes = Entity:GetTableValue(buffShow, "f_BuffVEXResource");
            beginName = Entity:GetTableValue(buffShow, "f_BuffStartName");
            loopName = Entity:GetTableValue(buffShow, "f_BuffLoopName");
            offsetPosTemp = Entity:GetTableValue(buffShow, "f_BuffVEXPosition");
            offsetPos_caster = Entity:GetTableValue(buffShow, "f_BuffVEXPosition_caster");
            duration = toNumber(Entity:GetTableValue(buffShow, "f_BuffStarDuration"));
        else
            effectRes = Entity:GetTableValue(buffShow, "b_BuffVEXResource");
            beginName = Entity:GetTableValue(buffShow, "b_BuffStartName");
            loopName = Entity:GetTableValue(buffShow, "b_BuffLoopName");
            offsetPosTemp = Entity:GetTableValue(buffShow, "b_BuffVEXPosition");
            offsetPos_caster = Entity:GetTableValue(buffShow, "b_BuffVEXPosition_caster");
            duration = toNumber(Entity:GetTableValue(buffShow, "b_BuffStarDuration"));
        end
        local skinId = FightManager.skinId2Fighter[caster.fighterId];

        local offsetPos = {};
        for k, v in pairs(offsetPosTemp) do
            offsetPos[k] = offsetPosTemp[k];
        end
        if offsetPos and #offsetPos >= 2 then
            if offsetPos[2] and offsetPos[2] ~= "" then
                local numY = tonumber(offsetPos[2])
                if self.isBoss then
                    numY = numY * (FightManager.bossScale * 0.85);
                    offsetPos[2] = numY;
                end
            end
        end
        if duration == nil then
            duration = 0;
        end

        --客户端演示没有这个值
        if buffServerId == nil or buffServerId == 0 or buffServerId == null then
            buffServerId = buffId
        end
        --不需要动作配合的buff，只播buffShow里的特效，需要动作配合的需要管理一下状态切换
        if buffData then
            self.buffDatas[buffServerId] = buffData;

            if not string.IsNilOrEmpty(buffShow.f_CastSE) then
                if self.roleObj then
                    AudioManager.Play(buffShow.f_CastSE, self.roleObj)

                else
                    AudioManager.Play(buffShow.f_CastSE)
                end
                log("buff_cast_sound_id:" .. buffShow.f_CastSE)
            end
        end

        --连线效果
        local linkEffect = false;
        if caster and offsetPos_caster ~= nil and offsetPos_caster ~= "" then
            linkEffect = true;
        end

        if effectRes ~= nil and effectRes ~= "" then
            if beginName ~= nil and beginName ~= "" then
                --log("=====================Entity:AddBuff2");
                if SkillManager.checkBuffSkin(effectRes) then
                    skinId = nil;
                end
                if skinId then
                    effectRes = effectRes .. "-" .. skinId;
                end
                --SpineEffect or nil, 非loop的不用等remove buff的时候删
                local param = nil;
                if front then
                    param = SpineEffectParam.Get(effectRes, Config.SortingDefault.Front_Buff, self.flip, beginName, buffShow.f_BuffId);
                else
                    param = SpineEffectParam.Get(effectRes, Config.SortingDefault.Back_Buff, self.flip, beginName, buffShow.f_BuffId);
                end
                local bossCfg = logicMgr.TrialsManager.GetBossConfigById(self.partnerModelId);
                if bossCfg ~= nil or GuildManager.checkIsGuildBossByModelId(self.partnerModelId) or FightManager.checkSoloBoss(self.partnerModelId) then
                    param.scale = param.scale * FightManager.bossScale;
                end
                param:setCaster(caster);
                param:setSpineType(EnumConst.SpineEffectType.BUFF);
                param:setSuffer(self);
                param:setDuration(duration / 1000);
                --param:setFollow(self:getFollowTrans(offsetPos));
                --logMy("add buff", offsetPos)
                param:setFollow(self:getFollowBone(offsetPos));

                if linkEffect then
                    param:setLinkFollow(caster:getFollowBone(offsetPos_caster));
                    local flip = getRoleFlip(self, caster);
                    param:setFlip(flip);
                end

                --self:playEffectResV2(param);
                if linkEffect then
                    --自己和自己连线效果不显示
                    if caster and self and caster ~= self then
                        self:playEffectResV2(param);
                    end

                end
                self:playEffectResV2(param);
            end

        end
        if loopName ~= nil and loopName ~= "" then
            local delay = (duration) / 1000;
            local param = nil;
            local key = nil;
            if front then
                key = buffFrontKey;
                param = SpineEffectParam.Get(effectRes, Config.SortingDefault.Role, self.flip, loopName, buffShow.f_BuffId);
            else
                key = buffBackKey;
                param = SpineEffectParam.Get(effectRes, Config.SortingDefault.Back_Buff, self.flip, loopName, buffShow.f_BuffId);
            end
            local bossCfg = logicMgr.TrialsManager.GetBossConfigById(self.partnerModelId);
            if bossCfg ~= nil or GuildManager.checkIsGuildBossByModelId(self.partnerModelId) or FightManager.checkSoloBoss(self.partnerModelId) then
                param.scale = param.scale * FightManager.bossScale;
            end
            param:setCaster(caster);
            param:setSuffer(self);
            param:setSpineType(EnumConst.SpineEffectType.BUFF);
            --param:setDuration(-1);
            param:setLoop(true);
            --param:setFollow(self:getFollowTrans(offsetPos));
            param:setFollow(self:getFollowBone(offsetPos));
            param:setDelay(delay);

            if linkEffect then
                param:setLinkFollow(caster:getFollowBone(offsetPos_caster));
                local flip = getRoleFlip(self, caster);
                param:setFlip(flip);
            end

            if self.buffEffect[buffServerId] then
                logWarn(string.format("add buff, duplicate buffServerId %s  %s  %s", self.fighterId, effectRes, buffServerId))
                if self.buffEffect[buffServerId][key] then
                    self.buffEffect[buffServerId][key]:stop();
                    self.buffEffect[buffServerId][key] = nil;
                end
                if self.buffEffect[buffServerId][buffFrontKey] == nil and self.buffEffect[buffServerId][buffBackKey] == nil then
                    self.buffEffect[buffServerId] = nil;
                end
            end

            self.buffEffect[buffServerId] = self.buffEffect[buffServerId] or {};
            if linkEffect then
                --自己和自己连线效果不显示
                if caster and self and caster ~= self then
                    self.buffEffect[buffServerId][key] = self:playEffectResV2(param);
                end
            else
                self.buffEffect[buffServerId][key] = self:playEffectResV2(param);
            end

            --logMy('addbuff', self.fighterId, buffServerId);

        end
    else
        if buffShow and buffShow.f_IsNega == 1 and front then
            --使用场景反色
            local time = 300 / FightManager.curTimeScale;--渐变时间
            local func = function(time)
                local startTime = 300 / FightManager.curTimeScale;
                if time <= 0 then
                    EffectUtil.SetNegaProgress(1);
                else
                    EffectUtil.SetNegaProgress((startTime - time * 1000) / startTime);
                end
            end
            FightManager.addUpdateFuncs(func, time)
        end
    end
    --处理跳字，仅支持前层，即跳字必须配置在buffShow前层特效里；
    if buffData and buffData.f_Tag and buffData.f_Tag ~= "" and front then
        local showTag = {}
        --过滤霸体buff

        for i = 1, #buffData.f_Tag do
            if buffData.f_Tag[i] ~= Config.BuffTagType.Tyrants then
                table.insert(showTag, buffData.f_Tag[i])
            end
        end
        if self.isShowDamage then
            local damageResult = {};
            damageResult.buffTag = showTag;
            showFightDamage(damageResult, self.roleObj, self);
        end
    end

    --[[
    local icon = Entity:GetTableValue(buffShow,"f_BuffIcon");
    if icon ~= nil and icon ~= "" then
        self:setBuff(icon,true);
    end
    ]]
end

function Entity:RemoveBuff(buffData, buffShow, buffServerId, caster)
    --log("=====================Entity:RemoveBuff");
    if buffShow.f_BuffId == 613104 then
        local a = 1;
    end
    if buffData.f_BuffEffect ~= nil and buffData.f_BuffEffect ~= "" then
        if buffData.f_BuffEffect == 48 then
            self.isMask = false;
        end
    end

    if buffData.f_Tag ~= nil and buffData.f_Tag ~= "" then
        for i, v in pairs(buffData.f_Tag) do
            if v == 1014 then
                --不飘字buff
                self.isShowDamage = true;
            end
            if v == 1015 then
                --拉取状态标记
                self.isHook = false;
            end
            if v == 1101 then
                --石化
                self.isPetrifaction = false;
                EffectUtil.SetObjPetrifaction(self.roleObj, 0)
                self:ResumeCurrentAction()
            end
            if v == 1 then
                --霸体标记
                self.isSuperArmor = false;
            end

            if v == 1031 then
                --大招进入飞行状态并清空连射
                self.isFly = false;
            end
        end
    end
    if (buffShow.f_BuffVEXResource ~= nil and buffShow.f_BuffVEXResource ~= "") or (buffShow.b_BuffVEXResource ~= nil and buffShow.b_BuffVEXResource ~= "") then
        local buffId = buffShow.f_BuffId;
        local effectRes = Entity:GetTableValue(buffShow, "f_BuffVEXResource");
        local endName = Entity:GetTableValue(buffShow, "f_BuffEndName");
        local offsetPosTemp = Entity:GetTableValue(buffShow, "f_BuffVEXPosition");
        local duration = toNumber(Entity:GetTableValue(buffShow, "f_BuffEndDuration"));

        local BackEffectRes = Entity:GetTableValue(buffShow, "b_BuffVEXResource");
        local BackEndName = Entity:GetTableValue(buffShow, "b_BuffEndName");
        local BackOffsetPos = Entity:GetTableValue(buffShow, "b_BuffVEXPosition");
        local BackDuration = toNumber(Entity:GetTableValue(buffShow, "b_BuffEndDuration"));

        local offsetPos = {};
        if offsetPosTemp and type(offsetPosTemp) == "table" then
            for k, v in pairs(offsetPosTemp) do
                offsetPos[k] = offsetPosTemp[k];
            end
        end
        if offsetPos and #offsetPos >= 2 then
            if offsetPos[2] and offsetPos[2] ~= "" then
                local numY = tonumber(offsetPos[2])
                if self.isBoss then
                    numY = numY * (FightManager.bossScale * 0.85);
                    offsetPos[2] = numY;
                end
            end
        end
        --客户端演示没有这个值
        if buffServerId == nil or buffServerId == 0 then
            buffServerId = buffId
        end

        --不需要动作配合的buff，只播buffShow里的特效，需要动作配合的需要管理一下状态切换
        if self.buffDatas[buffServerId] then
            self.buffDatas[buffServerId] = nil;
            local nextBuff = nil;
            if buffData and tonumber(buffData.f_BuffEffect) == EnumConst.BuffHitShowType.STUN then
                for k, v in pairs(self.buffDatas) do
                    if v and v.f_BuffEffect == EnumConst.BuffHitShowType.STUN then
                        nextBuff = v;
                        break ;
                    end
                end
                if nextBuff then
                    --to do changeAction，其他比如冰冻，石化等
                else
                    self:setAniState(Config.AnimationState.IDLE, nil, false, true);
                end
            end
        end
        --if effectRes == 'b012' then
        --    logError('remove buffshow '..effectRes..',  buffId = '..buffId);
        --end

        --if buffId == '10103' then
        --    logError('remove buffshow '..effectRes..',  buffId = '..buffId);
        --end

        if duration == nil then
            duration = 0;
        end
        --if self.buffEffect[buffId] ~= nil then
        if self.buffEffect[buffServerId] then
            if self.buffEffect[buffServerId][buffFrontKey] then
                self.buffEffect[buffServerId][buffFrontKey]:stop();
                self.buffEffect[buffServerId][buffFrontKey] = nil;
            end
            if self.buffEffect[buffServerId][buffBackKey] then
                self.buffEffect[buffServerId][buffBackKey]:stop();
                self.buffEffect[buffServerId][buffBackKey] = nil;
            end
            if self.buffEffect[buffServerId][buffFrontKey] == nil and self.buffEffect[buffServerId][buffBackKey] == nil then
                self.buffEffect[buffServerId] = nil;
            end
        else
            logWarn(string.format('RemoveBuff, buffEffect not found. (self.fighterId=%s,  effectRes=%s, buffId=%s, buffServerId=%s)', self.fighterId, effectRes, buffId, buffServerId))

            --local buffs = {};
            --for k,v in pairs(self.buffEffect) do
            --    table.insert(buffs, k);
            --end
            --logMy('buffEffect ', buffs);
            --
            --UnityEditor.EditorApplication.isPaused = true;
        end
        if self.hitShowType ~= EnumConst.HitShowType.HIDE then
            --角色在隐藏中不播放buff
            if endName ~= nil and endName ~= "" then
                --Entity:playEffectRes(effectRes, endName,Config.SortingDefault.Buff,pos,offsetPos,duration/1000,self.flip,nil,false,true,self.roleObj.transform,false);
                local skinId = FightManager.skinId2Fighter[caster.fighterId];
                if SkillManager.checkBuffSkin(effectRes) then
                    skinId = nil;
                end
                if skinId then
                    effectRes = effectRes .. "-" .. skinId;
                end
                local param = SpineEffectParam.Get(effectRes, Config.SortingDefault.Front_Buff, self.flip, endName, buffShow.f_BuffId);
                param:setDuration(duration / 1000);
                --param:setFollow(self:getFollowTrans(offsetPos));
                param:setFollow(self:getFollowBone(offsetPos));
                param:setSpineType(EnumConst.SpineEffectType.BUFF);
                param:setCaster(self);
                self:playEffectResV2(param);
            end
            if BackEndName ~= nil and BackEndName ~= "" then
                --Entity:playEffectRes(BackEffectRes, BackEndName,Config.SortingDefault.Buff,pos,offsetPos,duration/1000,self.flip,nil,false,true,self.roleObj.transform,false);
                local skinId = FightManager.skinId2Fighter[caster.fighterId];
                if SkillManager.checkBuffSkin(effectRes) then
                    skinId = nil;
                end
                if SkillManager.checkBuffSkin(effectRes) then
                    skinId = nil;
                end
                if skinId then
                    BackEffectRes = BackEffectRes .. "-" .. skinId;
                end
                local param = SpineEffectParam.Get(BackEffectRes, Config.SortingDefault.Back_Buff, self.flip, BackEndName, buffShow.f_BuffId);
                param:setDuration(BackDuration / 1000);
                --param:setFollow(self:getFollowTrans(offsetPos));
                param:setSpineType(EnumConst.SpineEffectType.BUFF);
                param:setFollow(self:getFollowBone(BackOffsetPos));
                self:playEffectResV2(param);
            end
        end
    else
        if buffShow and buffShow.f_IsNega == 1 then
            --取消场景反色
            EffectUtil.SetNegaProgress(0);
        end
    end

    if buffShow then
        if not string.IsNilOrEmpty(buffShow.f_RemoveSE) then
            if self.roleObj then
                AudioManager.Play(buffShow.f_RemoveSE, self.roleObj)

            else
                AudioManager.Play(buffShow.f_RemoveSE)
            end
            log("buff_remove_sound_id:" .. buffShow.f_RemoveSE)
        end
    end

    --战报移除buff效果,移除隐藏效果
    if buffData.f_BuffEffect ~= nil and buffData.f_BuffEffect ~= "" then
        local showType = toNumber(buffData.f_BuffEffect);
        if showType == EnumConst.BuffHitShowType.HIDE then
            self.hitShowType = EnumConst.HitShowType.NONE;
            if not Util.IsNull(self.skeletonAnimation) and not Util.IsNull(self.shadow.skeletonAnimation) then
                self.skeletonAnimation.Skeleton.A = 1;
                self.shadow.skeletonAnimation.Skeleton.A = 1;
            elseif not self.isEmpty then
                local str = self.roleObj and self.roleObj.name or "";
                --printError("Skeleton有问题", "name = " .. str);
            end

            if self.headBar and self.hideHeadBar == 1 then
                self:setHeadBar(true)
                self.hideHeadBar = 0
            end
            for k, v in pairs(self.buffEffect) do
                for i, j in pairs(v) do
                    if not Util.IsNull(j.skeletonAnimation) then
                        j.skeletonAnimation.Skeleton.A = 1
                    elseif not self.isEmpty then
                        local str = j.roleObj and j.roleObj.name or "";
                        --printError("Skeleton有问题", "name = " .. str);
                    end
                end
            end
        end
        if buffData.f_Tag[1] == Config.BuffTagType.Nihility and not self.isMask then
            self.skeletonAnimation.Skeleton.A = 1;
        end
    end
    --[[
    self:setBuff(nil,false);
    ]]
end

function Entity:RemoveAllBuff()
    for k, v in pairs(self.buffEffect) do
        if v then
            if v[buffFrontKey] then
                v[buffFrontKey]:stop();
            end
            if v[buffBackKey] then
                v[buffBackKey]:stop();
            end
        end
    end

    self.buffEffect = {};
end

function Entity:ChangeBuffPool(buffPoolType, buffPoolMax, buffPoolCurrent)
    self:setShield(buffPoolCurrent, buffPoolMax)
end

function Entity:ChangeBuffOverlay(buffShow, buffServerId, buffOverlay)
    if self.buffEffect[buffServerId] then
        --logMy('ChangeBuffOverlay, playAction ', self.fighterId, tostring(buffOverlay), buffServerId);
        if self.buffEffect[buffServerId][buffFrontKey] then
            self.buffEffect[buffServerId][buffFrontKey]:playAction(tostring(buffOverlay));
        end
        if self.buffEffect[buffServerId][buffBackKey] then
            self.buffEffect[buffServerId][buffBackKey]:playAction(tostring(buffOverlay));
        end
    else
        if buffShow.f_BuffVEXResource ~= nil and buffShow.f_BuffVEXResource ~= "" then
            local buffId = buffShow.f_BuffId;
            local effectRes = Entity:GetTableValue(buffShow, "f_BuffVEXResource");
            logWarn(string.format("ChangeBuffOverlay, buffEffect not found. effectRes=%s   buffId=%s   buffServerId=%s", effectRes, buffId, buffServerId))
        end
    end
    if buffShow then
        if self.buffsOverlay[buffShow.f_BuffId] ~= nil then
            if self.buffsOverlay[buffShow.f_BuffId] < buffOverlay then
                --处理跳字
                local buffData = G.dataTable["t_buff"][tostring(buffShow.f_BuffId)];
                if buffData and buffData.f_Tag and buffData.f_Tag ~= "" then
                    if self.isShowDamage then
                        local damageResult = {};
                        damageResult.buffTag = buffData.f_Tag;
                        showFightDamage(damageResult, self.roleObj, self);
                    end
                end
            end
        end
        self.buffsOverlay[buffShow.f_BuffId] = buffOverlay;
    end
end

function Entity:removeRandomBuff(fight, target, result, type)
    local buffs = {};
    local iterator = target.buffs;
    for k, v in pairs(iterator) do
        if v.buffBean.f_BuffType == type then
            table.insert(buffs, v);
        end
    end

    if #buffs > 0 then
        local index = FightManager.getRandomInt(fight, #buffs);
        local buff = buffs[index + 1];
        fightLog("[SKILL]" .. target.fighterId .. "被移除buff" .. buff.modelId);
        BuffManager.removeFighterBuff(fight, target, buff);
    end
end

function Entity:updateBuffState()
    if FighterManager.isInstate(self, EnumConst.FighterStateEnum.CAN_NOT_MOVE) and not self.isDead and self.aniState == Config.AnimationState.RUN then
        self.playIdle();
    end
    self:showSpecialAnimation();
end

function Entity:stateBegin(is)
    self.isBegin = is;
end

function Entity:damage(type, damage, showDamage)
    --fightShowLog("[HP pre]".."fighterId:"..self.fighterId.." HP:"..self.hp.." Damage:"..damage.." type:"..type);
    if type == Config.damageType.normal or type == Config.damageType.crit then
        if self.partnerModelId == "27" then
            local a = 1;
        end
        self.hp = self.hp - toNumber(damage);
        if (self.hp <= 0 or FightManager.getDamageAfterCurrentFrame(self.fighterId) == nil) and self.needDead then
            self.hp = 0;
            self:setDead(true);
            --self:setDead();
            --FireEvent(Config.FightEvent.ROLE_DEAD,self);
        end
        self:setHP(self.hp, self.maxHP);
        if self.teamIndex == 2 then
            FireEvent(Config.EventType.Fight_Update_BossHP, toNumber(damage));
        else
            FireEvent(Config.EventType.Fight_Update_HeroHP);
        end
    elseif type == Config.damageType.dodge then
    elseif type == Config.damageType.immunity then
    elseif type == Config.damageType.heal then
        self.hp = self.hp + toNumber(damage);
        if self.hp > self.maxHP then
            self.hp = self.maxHP;
        end
        --死了可以复活，然后加血。但不应该直接加血加回来。
        if (self.isDead or self.isDeading) and self.hp > 0 then
            print(string.format("这个是战报顺序问题，客户端想办法处理.一口奶活了===fightid==%d,奶量=%d", self.fighterId, damage))
            --self:setAniState(Config.AnimationState.IDLE, nil, false);
            --self.isDeading = false;
            --self.isDead = false;
            --self.roleObj:SetActive(true);
            return
        end

        self:setHP(self.hp, self.maxHP);
        if self.teamIndex == 2 then
            FireEvent(Config.EventType.Fight_Update_BossHP);
        else
            FireEvent(Config.EventType.Fight_Update_HeroHP);
        end
    elseif type == Config.damageType.sp then
        self.energy = self.energy + toNumber(damage);
        if self.energy > self.maxEnergy then
            self.energy = self.maxEnergy;
        end
        local spPercent = self.energy / self.maxEnergy;
        self:setSP(spPercent);
        FireEvent(Config.EventType.Fight_Update_HeroEnergy, self, spPercent);

    elseif type == Config.damageType.shields then
        --护盾
        --跳字吸收
        --local num = self.shield - damage
        --self:setShield(num)

    end

    if FightManager.FightDebug then
        --if type == Config.damageType.normal or type == Config.damageType.crit or type == Config.damageType.heal then
        --    fightShowLog("[HP]".."fighterId:"..self.fighterId.." HP:"..self.hp.." Damage:"..damage);
        --end

        fightShowLog("[HP]" .. "fighterId:" .. self.fighterId .. " HP:" .. self.hp .. " Damage:" .. damage .. " type:" .. type);
    end

    if showDamage then
        if self.isShowDamage then
            local damageResult = {};
            damageResult.damage = damage;
            damageResult.type = type
            showFightDamage(damageResult, self.roleObj, self);
        end
    end
    if self.isWaitDeadDam then
        self:setDead()
    end
end

function Entity:onUpdateBar()
    local camera = FightManager.getCamera();
    if self.headBar ~= nil and camera ~= nil then
        if self.isBegin then
            self.hpCtrl.selectedIndex = 1
        end
        local pos = Util.WorldToScreenPoint(camera, self.roleObj.transform.position);
        local tpos = Vector2.New(0, 0)
        tpos:Set(pos.x + Screen.width * 0.5, Screen.height * 0.5 - pos.y)
        local pt = FairyGUI.GRoot.inst:GlobalToLocal(tpos);
        self.headBar:SetXY(pt.x - Config.uiXOffset, pt.y)

    end
end

--通用调用接口
--禁止调用 self.headBar.visible
--@visible 是否显示
--@withtable 是否使用配表
function Entity:setHeadBar(visible, withtable)
    if self.headBar ~= nil then
        self:onUpdateBar();
        --配表是否显示血条 f_LifeBar
        self.headBar.visible = visible and (self.f_LifeBar == 0 or withtable)
    end
end

function Entity:setHP(hp, max)
    if self.isDead or self.isDeading then
        return ;
    end

    self.hp = tonumber(hp);

    local max_hp = 0;
    local hpPercent = 1;
    local shieldPercent = 0;
    if self.shield > 0 and self.shieldNum > 0 then
        if self.shield <= max - self.hp then
            shieldPercent = (self.shield + hp) / max;
            hpPercent = self.hp / max;
        else
            max_hp = self.hp + self.shield;
            shieldPercent = 1;
            hpPercent = self.hp / max_hp;
        end
    else
        max_hp = max;
        hpPercent = self.hp / max_hp;
    end

    if self.headBar ~= nil then
        self.hpSlider.value = hpPercent * 100;
    end
    if self.hp2Slider ~= nil then
        self.hp2Slider.value = shieldPercent * 100;
    end
end

function Entity:setShield(value, max)
    self.shield = tonumber(max);
    self.shieldNum = tonumber(value);
    self:setHP(self.hp, self.maxHP);
end

function Entity:setSP(sp)
    if sp == nil then
        return ;
    end
    if self.spSlider ~= nil then
        self.spSlider.value = sp * 100;
    end
end

function Entity:setBuff(icon, show)
    if show then
        self:setHeadBar(true)
        self.buffIcon.visible = true;
        self.buffIcon.url = "ui://buffatlas/" .. icon;
        --resMgr:LoadIconFromPrefab("buffatlas", icon, function(sp)
        --end);
    else
        self.buffIcon.visible = false;
    end
end

function Entity:getDeadState()
    return self.isDead or self.isDeading or self.roleObj == nil
end

function Entity:getDead()
    return self.isDead;
end

function Entity:setAdditionalState(state)
    if self.isShowDamage then

        if state == EnumConst.AdditionalStateType.BLOCK then
            --printError("fighterId==额外状态格挡=", self.fighterId, state);
            local damageResult = {};
            damageResult.addState = state;
            showFightDamage(damageResult, self.roleObj, self);
        elseif state == EnumConst.AdditionalStateType.SUPER_ARMOR then
            local damageResult = {};
            damageResult.addState = state;
            showFightDamage(damageResult, self.roleObj, self);
        end
    end
end

function Entity:setDead(force)
    --logMy('setDead', self.fighterId);

    if self.isDead then
        --logMy('setDead FireEvent', self.fighterId);
        return ;
    end
    --if self.hp > 0 then
    --    self:damage(Config.damageType.normal, self.hp, true)
    --end
    local damageInfo = FightManager.getDamageAfterCurrentFrame(self.fighterId)--自己身上没完成的跳字
    local beDamageInfo = FightManager.getDamageAfterOtherFrame(self.fighterId);--自己未打出的伤害
    if not force and table.getn(beDamageInfo) ~= 0 and damageInfo ~= nil then
        self.delayCallDuration = delayDeadTime;
        local duration = delayDeadTime;
        if beDamageInfo and not damageInfo then
            local playingEffect = self:getSkillEffect(beDamageInfo.skillId);--自己还在播放的特效
            if playingEffect and playingEffect.duration and damageInfo == nil then
                duration = playingEffect.duration;--加一帧防止出问题
                if duration < delayDeadTime then
                    --动画播放时间小于延时死亡时间 延时死亡时间改为播放时间
                    self.delayCallDuration = duration;
                end
            end
        end

        self.isWaitDeadDam = true;
        self.delayCallFunc = function()
            --强制三帧后死亡
            self:setDead(true);
        end

        if damageInfo then
            if self.hp <= 0 then
                self:setDead(true);
            else
                self.needDead = true;
                return ;
            end
            self.isWaitDeadDam = false;
        end
    elseif (damageInfo and table.getn(damageInfo) > 0) or (beDamageInfo and table.getn(beDamageInfo)) then
        if damageInfo then
            for i, v in pairs(damageInfo) do
                if v and type(v) == "table" and v.isFrame then
                    --直接把没打完的伤害爆出来（基本是鞭尸
                    local damage = v.damage;
                    local damageType = v.damageType;
                    v.used = true;
                    self:damage(damageType, damage, true)
                end
            end
        end
        if beDamageInfo then
            for i, v in pairs(beDamageInfo) do
                if v and type(v) == "table" then
                    --直接把没打完的伤害爆出来（基本是鞭尸
                    local damage = v.damage;
                    local damageType = v.damageType;
                    v.used = true;
                    local targetId = v.targetId;
                    for k, j in pairs(FightManager.fighterList) do
                        if targetId == j.fighterId then
                            --把该打在别人身上的伤害打出来
                            if not logicMgr.SkillManager.checkIsOut(v.skillId) then
                                table.insert(FightManager.damageTemp, v);
                                j:damage(damageType, damage, true)
                            else
                                v.used = false;
                            end
                        end
                    end
                end
            end
        end
    end

    if self.delayCallFunc then
        self.delayCallFunc = nil;
        self.delayCallDuration = 0;
    end

    if self.teamIndex == 1 then
        --死亡
        local _index = Mathf.Random(20, 21)
        local _partnerModelId = self["partnerModelId"]
        local _skinId = 0
        local _interactionTag = AudioManager.InteractionTagTable[_index].Tag
        AudioManager.PlayInteractionVoice(_partnerModelId, _skinId, _interactionTag)
    end
    local modelId = self.partnerModelId;
    if modelId == "610" and self.isHero then
        modelId = "61";
        local bindingEntity = FightManager.getEntityByModel("611", self.teamIndex);
        bindingEntity:setAniState(Config.AnimationState.DEAD);
    end
    FireEvent(Config.EventType.Fight_Dead_id, { id = modelId, teamId = self.teamIndex })
    self:RemoveSkillEffect();
    self:setAniState(Config.AnimationState.DEAD, nil, false);
    self.isDeading = true;
    self:setHeadBar(false, false)
    self:setAfterImgState(false);
    self.afterImageTab = {};
    self:recoverPosition();
end

function Entity:setPosition(pos)
    self._localPosition:SetV(pos)
    if self.roleObj ~= nil then
        Util.Lua_SetLocalPositionXYZ(self.roleObj, pos.x, pos.y, pos.z)
        if self.headBar ~= nil then
            local camera = FightManager.getCamera();
            if camera ~= nil then
                local pos = Util.WorldToScreenPoint(camera, self.roleObj.transform.position);
                local tpos = Vector2.New()
                tpos:Set(pos.x + Screen.width * 0.5, Screen.height * 0.5 - pos.y)
                local pt = FairyGUI.GRoot.inst:GlobalToLocal(tpos);
                self.headBar:SetXY(pt.x - Config.uiXOffset, pt.y)

            end
        end
    end
end

function Entity:getPosition()
    self._localPosition:Set(ObjUtil.GetLocalPosition(self.roleObj.transform))
    return self._localPosition
end

function Entity:getWorldPosition()
    self._worldPosition:Set(ObjUtil.GetPosition(self.roleObj.transform))
    return self._worldPosition
end

function Entity:getModel()
    if self.roleObj ~= nil then
        return self.roleObj;
    end
    return nil;
end

function Entity:getModelId()
    return self.partnerModelId;
end

function Entity:setActive(value)
    if self.roleObj ~= nil then
        self.roleObj:SetActive(value);
        if value == false then
            self:setAfterImgState(value);
        end
        if self.isBegin then
            self:setHeadBar(value)
        end
    end
end

function Entity:setAfterImgState(state)
    for k, v in pairs(self.afterImageTab) do
        if not HelperFunc.IsNull(v) then
            v:SetActive(state);
        end
    end
end

function Entity:setRunPos(pos)
    self.moveTarget = nil;
    self.moveEnd = pos;
    local x, y, z = Util.Lua_GetLocalPositionXYZ(self.roleObj, 0, 0, 0);
    self.moveBegin = Vector3(x, y, z);
    self.moveDirection = Vector3.Normalize(self.moveEnd - self.moveBegin);
    self.moveType = EnumConst.MoveType.NONE;
    self:setAniState(Config.AnimationState.RUN);
end

function Entity:setRunTarget(target)
    self.moveTarget = target;
    self.moveEnd = nil;
    local x, y, z = Util.Lua_GetLocalPositionXYZ(self.roleObj, 0, 0, 0);
    self.moveBegin = Vector3(x, y, z);
    self.moveDirection = nil;
    self.moveType = EnumConst.MoveType.Target;
    self:setAniState(Config.AnimationState.RUN);
end

function Entity:setWalkPos(pos)
    --logMy('setWalkPos', pos);

    self.moveTarget = nil;
    self.moveEnd = pos;
    local x, y, z = Util.Lua_GetLocalPositionXYZ(self.roleObj, 0, 0, 0);
    self.moveBegin = Vector3(x, y, z);
    self.moveDirection = Vector3.Normalize(self.moveEnd - self.moveBegin);
    self.moveType = EnumConst.MoveType.NONE;
    self:setAniState(Config.AnimationState.WALK, nil, nil, true);
end

function Entity:setWalkTarget(target)
    self.moveTarget = target;
    self.moveEnd = nil;
    local x, y, z = Util.Lua_GetLocalPositionXYZ(self.roleObj, 0, 0, 0);
    self.moveBegin = Vector3(x, y, z);
    self.moveDirection = nil;
    self.moveType = EnumConst.MoveType.Target;
    self:setAniState(Config.AnimationState.WALK);
end

function Entity:setWalkDirection(dir)
    --logMy('setWalkDirection', dir);

    self.moveTarget = nil;
    self.moveEnd = nil;

    local x, y, z = Util.Lua_GetLocalPositionXYZ(self.roleObj, 0, 0, 0);
    self.moveBegin = Vector3(x, y, z);
    self.moveDirection = dir;
    self.moveType = EnumConst.MoveType.Direction;
    self:setAniState(Config.AnimationState.WALK);
end

function Entity:setAttackTarget(target)
    if not self.isDead and not self.isDeading then
        self.target = target;
    end
end

function Entity:getTarget()
    return self.target;
end

function Entity:getAttack()
    return self.canAttack;
end

function Entity:setOrder(depth)
    if (not self.isEmpty) then
        if FightManager.cutInState then
            Util.SetOrder(self.roleObj.transform:Find("Animation").gameObject, depth + Config.SortingDefault.FullScreen);
            if not HelperFunc.IsNull(self.lihuiSkeleton) then
                Util.SetOrder(self.lihuiSkeleton.gameObject, depth + Config.SortingDefault.FullScreen);
            end
        else
            Util.SetOrder(self.roleObj.transform:Find("Animation").gameObject, depth);
            if not HelperFunc.IsNull(self.lihuiSkeleton) then
                Util.SetOrder(self.lihuiSkeleton.gameObject, depth);
            end
        end
    end

end

function Entity:GetTableValue(tableData, valKey)
    local val = nil;
    if tableData ~= nil then
        val = tableData[valKey];
    else
        log(valKey);
        logError("表为空!!!");
    end
    return val;
end

function Entity:setFlip(flip)

    --if self.fighterId == 1 then
    --    logMy('setFlip.', flip, self.roleObj.name);
    --end

    self.flip = flip;
    --Util.SetFlipX(self.roleObj.transform:Find("Animation").gameObject,flip);
    Util.SetFlipX(self.skeletonAnimation, flip);

    if self.shadow then
        self.shadow:setFlip(flip);
    end
end

function Entity:updateFlip()
    self:setFlip(self.flip);
end

function Entity:playCVSoundByName(mySelf, skillShow)
    local _skillSound = Entity:GetTableValue(skillShow, "f_SkillCv");
    if not string.IsNilOrEmpty(_skillSound) then
        AudioManager.Play(_skillSound, mySelf.roleObj)
    end
end

--播放释放技能音效
function Entity:playSkillAudio(mySelf, skillShow)
    local audioSkill = Entity:GetTableValue(skillShow, "f_SkillAudio");
    if not string.IsNilOrEmpty(audioSkill) then
        local _skillId = tonumber(skillShow["f_SkillID"])
        --戴莉必杀技的C段，stop之前的持续的B段音效
        if Mathf.Floor(_skillId / 1000) == 222 and Mathf.Floor(_skillId % 10) == 2 then
            AudioManager.Stop(audioSkill, mySelf.roleObj)
            return
        end
        AudioManager.Play(audioSkill, mySelf.roleObj)
    end
end

--播放受击音效
function Entity:playHitAudio(mySelf, skillShow)

    local _audioId = Entity:GetTableValue(skillShow, "f_HitAudio")
    if string.IsNilOrEmpty(_audioId) or _audioId == 0 or not FightManager.IsBattleFight then
        return
    end
    --logError("playHitAudio ".._audioId)
    local _battleSoundInfo = G.dataTable["t_sound_se_battle"][tostring(_audioId)]
    if _battleSoundInfo and not string.IsNilOrEmpty(_battleSoundInfo.f_Event) then
        if string.match(_battleSoundInfo.f_Event, AudioManager.HIT_SUFFIX) then
            local _heroCfg = G.dataTable["t_hero"][tostring(mySelf.partnerModelId)]
            local _soundTexture = _heroCfg["f_SoundTexture"]
            if _soundTexture and #_soundTexture == 1 then
                AudioManager.SetSwitch(_soundTexture[1][1], _soundTexture[1][2], mySelf.roleObj)
            end
        end
        AudioManager.Play(_audioId, mySelf.roleObj)
    end
end

function Entity:playBackGroundFullScreen(skillShow, addTime)

    --背景特效
    local effectBGRes = Entity:GetTableValue(skillShow, "f_BackGroundResource");
    local actionBGName = Entity:GetTableValue(skillShow, "f_BackGroundName");
    local effBGObj = nil;
    if effectBGRes ~= nil and actionBGName ~= "" and FightManager.sceneEffectObj == nil then

        local duration = Entity:GetTableValue(skillShow, "f_BackGroundDuration") / EnumConst.THOUSANDTH;
        if addTime then
            duration = duration + addTime;
        end
        --local effectRes = "fullscreen"; --"fullScreenBlack"
        --local actionName = 'idle';
        --local duration = 3;

        --duration = duration * self.timeScale;
        --local offsetPos = "0,0";
        --local scale = 15000;
        local vPos = Vector3(307.4, 300, 300);
        --self.fullScreen = Entity:playEffectRes(effectRes, actionName,Config.SortingDefault.FullScreen, vPos, offsetPos, duration, false, nil,false,false,nil,false);
        local skinId = FightManager.skinId2Fighter[self.fighterId];
        if skinId then
            effectFRes = effectFRes .. "-" .. skinId;
        end
        local param = SpineEffectParam.Get(effectBGRes, Config.SortingDefault.Scene, flip, actionBGName, skillShow.f_SkillID);
        param:setDuration(duration);
        param:setSpineType(EnumConst.SpineEffectType.SKILL);
        param:setPosition(vPos);
        effBGObj = self:playEffectResV2(param);
        FightManager.sceneEffectObj = effFObj;
    end

    --logMy('playFullScreen', effectRes, actionName, duration);
end

--速度线特效
function Entity:playFullScreen(skillShow, addTime)

    --printError(skillShow.f_SkillName)
    local effectRes = Entity:GetTableValue(skillShow, "f_FullScreenResource");
    local actionName = Entity:GetTableValue(skillShow, "f_FullScreenName");
    local duration = Entity:GetTableValue(skillShow, "f_FullScreenDuration") / EnumConst.THOUSANDTH;
    if addTime then
        duration = duration + addTime;
    end
    --local effectRes = "fullscreen"; --"fullScreenBlack"
    --local actionName = 'idle';
    --local duration = 3;

    --duration = duration * self.timeScale;
    if effectRes ~= nil and effectRes ~= "" then
        --local offsetPos = "0,0";
        --local scale = 15000;
        local vPos = self:getWorldPosition(); --Vector3(307.4,300,300);
        --self.fullScreen = Entity:playEffectRes(effectRes, actionName,Config.SortingDefault.FullScreen, vPos, offsetPos, duration, false, nil,false,false,nil,false);
        local skinId = FightManager.skinId2Fighter[self.fighterId];
        local param = SpineEffectParam.Get(effectRes, Config.SortingDefault.FullScreen, self.flip, actionName, skillShow.f_SkillID);
        param:setDuration(duration);
        param:setPosition(vPos);
        param:setSpineType(EnumConst.SpineEffectType.SKILL);
        param:setCaster(self);
        self.fullScreen = self:playEffectResV2(param);

        --logMy('playFullScreen startTime', Time.time, duration);
    end

    --logMy('playFullScreen', effectRes, actionName, duration);
end

function Entity:stopFullScreen()
    if self.fullScreen ~= nil then
        self.fullScreen:stop();
        self.fullScreen = nil;
    end
end

function Entity:playCutIn(skillShow)
    local modelId = self.partnerModelId;
    if modelId == "7054" then
        modelId = "54"
    end
    if modelId == "7063" then
        modelId = "63"
    end

    FireEvent(Config.EventType.Fight_Update_CutIn, modelId) ;
end
function Entity:playSceneCardEffect(skillShow)
    --printError(self.partnerModelId, self.model)
    if not HelperFunc.IsNull(self.lihuiSkeleton) then
        self.lihuiSkeleton.gameObject:SetActive(true);

        local pathName = self.partnerModelId;
        if pathName == "611" then
            pathName = "61";
        end

        local skinId = logicMgr.SkinManager.getHeroSkinId(pathName);
        if self.skinId then
            skinId = self.skinId;
        end
        local cfg = dataTable.getDataTableByStringId("t_skin", skinId)
        local heroSkinName = "";
        if AppConst.drawingState ~= 0 and self.isPa then
            heroSkinName = cfg.f_FightAnim_PA;
        else
            heroSkinName = cfg.f_FightAnim;

        end
        Util.SetSkin(self.lihuiSkeleton.gameObject, heroSkinName);
        Util.PlayAction(self.lihuiSkeleton, "idle", false);
    end
end

function Entity:ShakeCamera(type, time)
    local camera = FightManager.getCamera();
    local animator = camera.transform:GetComponent("Animator");
    if animator ~= nil then
        local shakeTime = time;
        animator:SetTrigger("shake1");
        -- Util.WaitForSeconds(function()
        --     animator:ResetTrigger("shake1");
        --     animator:ResetTrigger("shake2");
        --     animator:SetTrigger("idle")
        -- end, shakeTime / 1000);

        local func = function()
            animator:ResetTrigger("shake1")
            animator:ResetTrigger("shake2")
            animator:SetTrigger("idle")
        end;
        local times = shakeTime;

        FightManager.addDelayFuncs(func, times);
    end
end

function Entity:beginAttack(skillId, skillData, skillShow, targetRole)
    if self.isDead or targetRole.isDead then
        return ;
    end

    self.canAttack = false;
    local guideTime = Entity:GetTableValue(skillData, "f_GuideTime");
    -- Util.WaitForSeconds(function()
    --     self.canAttack = true;
    -- end, tonumber(guideTime / 1000));
    ubattletimer.delayCall(function()
        self.canAttack = true
    end, tonumber(guideTime))

    self:setAniState(Config.AnimationState.IDLE);

    self.playCoroute = coroutine.start(self.playSkillCoroutine, self, skillId, skillData, skillShow, targetRole);
end

function Entity:breakSkill()
    if self.playCoroute ~= nil then
        coroutine.stop(self.playCoroute);
        self:setAniState(Config.AnimationState.IDLE);
    end
end

function Entity:playAnimation(animationName, loop, time, isEffect)

    --GameObject obj, string animName, bool loop = true, float time = -1, bool isEffect = false
    if loop == nil then
        loop = true;
    end

    if time == nil then
        time = -1;
    end

    if isEffect == nil then
        isEffect = false;
    end
    local timeRate = 1;
    --
    --logMy('self:getAnimationName(aniName)', aniName, animationName)
    --local isSkill = string.find(animationName, "skill", 1)
    --local isHit = string.find(animationName, "hit", 1)
    --if animationName == "attack" or (isSkill and not isHit) then
    --    local durTime = self.skeletonAnimation.skeleton.Data:FindAnimation(animationName).Duration
    --    local orgFrame = durTime / (EnumConst.FIGHT_FRAME / EnumConst.THOUSANDTH)
    --    timeRate = orgFrame / (orgFrame - 2)
    --end
    local duration = Util.PlayAction(self.skeletonAnimation, animationName, loop, time, isEffect, self.timeScale * timeRate);--self.timeScale);

    --同步shadow动作
    if self.shadow then
        self.shadow:playAnimation(animationName, loop, time, isEffect, self.timeScale * timeRate);--self.timeScale)
    end

    return duration;
end

function Entity:playAction(actionName, loop, time, isEffect)
    --GameObject obj, string animName, bool loop = true, float time = -1, bool isEffect = false
    if loop == nil then
        loop = true;
    end

    if time == nil then
        time = -1;
    end

    if isEffect == nil then
        isEffect = false;
    end

    --
    --if actionName == 'idleBattle' and loop ~= true then
    --    logMy('idleBattle not loop.', animationName, actionName, self.roleObj.name);
    --end

    --
    local animationName = self:getAnimationName(actionName);

    --if animationName == 'fidle' and loop ~= true then
    --    logMy('fidle not loop.', animationName, actionName, self.roleObj.name);
    --end

    if animationName ~= nil and animationName ~= 'nil' then
        return self:playAnimation(animationName, loop, time, isEffect);
    else
        if not self.isEmpty then
            logMy('getAnimationName() is ', animationName, actionName, self.roleObj.name);
        end
        return 0;
    end

end

--function Entity:initBoneTrans()
--    --锚点
--    self.boneTransforms = {};
--    self.boneTransforms['default'] = self.roleObj.transform;
--
--    for k, v in pairs(Config.RoleBoneNames) do
--        self.boneTransforms[v] = Util.GetSpineBoneAsTransform(self.skeletonAnimation, v);
--    end
--
--    --logMy('initBoneTrans', self.boneTransforms);
--end

function Entity:initBones()
    --锚点
    self.bones = {};

    for k, v in pairs(Config.RoleBoneNames) do
        --logMy("获取锚点",v)
        if self.skeletonAnimation then
            self.bones[v] = self.skeletonAnimation.Skeleton:FindBone(v);
        end
    end

    --logMy('initBones', self.bones);
end

--function Entity:getBoneTrans(boneName)
--    return self.boneTransforms[boneName] or self.boneTransforms['default'];
--end

function Entity:getBone(boneName)
    local bone = nil;
    if (self.isEmpty) then
        bone = self.roleObj.transform
    else
        bone = self.bones[boneName];
    end

    local trans = nil
    if not HelperFunc.IsNull(self.roleObj) then
        trans = self.roleObj.transform
    end

    return bone, trans;
end

---- positionDesc:  '0, 0, body_drop',  '1, 1.5'
--function Entity:getFollowTrans(positionDesc)
--    local offset = {0, 0}
--    local boneName = Config.RoleBoneNames_default
--
--    if positionDesc ~= nil then
--        local tmp = string.split(positionDesc,",");
--
--
--        if #tmp >= 3 then
--            boneName = tmp[3]
--        end
--
--        if #tmp >= 2 then
--            offset = {tmp[1], tmp[2]}
--        end
--
--    end
--
--    local trans = self:getBoneTrans(boneName)
--
--    return trans, offset
--end

-- positionDesc:  '0, 0, body_drop',  '1, 1.5'
function Entity:getFollowBone(positionDesc)
    local offset = { 0, 0 }
    local boneName = nil

    if positionDesc ~= nil then
        local tmp = positionDesc --string.split(positionDesc, ",");

        if #tmp >= 3 then
            boneName = tmp[3]
        end

        if #tmp >= 2 then
            offset = { tmp[1], tmp[2] }
        end

    end

    local bone, trans = self:getBone(boneName)

    return trans, offset, bone, self.skeletonAnimationTrans
end

local cachewPosition = Vector3.New(0, 0, 0)
function Entity:getOffsetPosition(positionDesc, flip)
    local trans, offset, bone, skeletonAnimationTrans = self:getFollowBone(positionDesc);

    local IsNull = HelperFunc.IsNull
    local scale = { x = 1, y = 1, z = 1 }
    if not IsNull(self.roleObj) and not IsNull(self.roleObj.transform) then
        scale.x = self.roleObj.transform.localScale.x
        scale.y = self.roleObj.transform.localScale.y
        scale.z = self.roleObj.transform.localScale.z
    end
    if not IsNull(bone) and not IsNull(skeletonAnimationTrans) then
        cachewPosition.x, cachewPosition.y, cachewPosition.z = Util.Lua_GetBoneWorldXYZ(bone, skeletonAnimationTrans, 0, 0, 0)

    elseif not IsNull(trans) then
        cachewPosition.x, cachewPosition.y, cachewPosition.z = Util.Lua_GetPositionXYZ(trans, 0, 0, 0)
    end

    local offsetX = scale.x * toNumber(offset[1]);
    local offsetY = scale.y * Mathf.Cos(Mathf.PI / 6 / 3 * 4) * toNumber(offset[2]);
    local offsetZ = scale.z * Mathf.Sin(Mathf.PI / 6 / 3 * 4) * toNumber(offset[2]);

    if flip then
        offsetX = -offsetX;
        --else
        --    offsetX = offsetX;
    end

    return Vector3(cachewPosition.x + offsetX, cachewPosition.y + offsetY, cachewPosition.z + offsetZ);

end

function Entity:getSkeletonAnimation()
    return self.skeletonAnimation;
end

function Entity:setTimeScale(timeScale)
    ----test
    --if self.fighterId == 1 then
    --    self.timeScale = timeScale;  -- 入场不需要加速，所以在正式开始战斗后再设置timeScale
    --end
end

function Entity:onEntranceFinish()
    --test
    --self:setTimeScale(2);
end

function Entity:showAfterimge(param, deltaTime)
    --logMy('in showAfterimge', param, deltaTime, self.modelName);

    if param == nil or param.afterimage ~= 1 then
        return
    end

    param.time = param.time + deltaTime;
    if param.time >= param.interevalTime then
        param.time = param.time - param.interevalTime;

        --create effect
        local resName = self.model;-- .. self.fighterId;
        local originalSpineGo = self.skeletonAnimationTrans.gameObject;
        local effectGo = Util.CreateAfterimage(resName, originalSpineGo);
        --logMy('in showAfterimge');

        --init position
        if effectGo then
            local pos = self:getWorldPosition();
            Util.Lua_SetLocalScaleXYZ(effectGo.transform, pos.x, pos.y, pos.z)
        end
    end
end

function Entity:showAfterimgeSequence(startPos, endPos)

    local v = (G.dataTable["t_effect1"] or {})[tostring(self.model)];
    if v then
        local color = v.f_Color -- decodeJsonStrToTabel(v.f_Color)
        local outlineColor = Color(color[1], color[2], color[3], color[4]); --v.f_Color

        local dir = endPos - startPos;
        --dir.z = 0;
        local length = dir.magnitude;

        local count = math.floor(length / toNumber(v.f_Count));
        --local delayEndTime = v.f_DelayEndTime;
        --local delayIncTime = v.f_DelayIncTime;

        local originalSpineGo = self.skeletonAnimationTrans.gameObject;
        --logMy('in showAfterimgeSequence', resName, startPos, endPos, outlineColor, count, delayEndTime, delayIncTime);

        Util.ShowAfterimageSequence(self.model, originalSpineGo, startPos, endPos, outlineColor, count, v.f_DelayEndTime, v.f_DelayIncTime, v.f_AnimationName, v.f_FrameNum);
    end

end

--function Entity:showKillEffect()
--	if self.headBar then
--		if self.killNum == nil then
--			self.killNum = 1;
--		else
--			self.killNum = self.killNum + 1;
--		end
--		self.ctrlKillShow.selectedIndex = self.killNum - 1;
--		self.headBarKillShow.visible = true;
--		self.aniKillShow:Stop();
--		self.aniKillShow:Play(function()
--			self.headBarKillShow.visible = false;
--
--		end)
--	end
--end

function Entity:showEnergyEff(skillId)
    if self.headBar and self.teamIndex == 1 then
        if skillId then
            local skillInfos = logicMgr.SkillManager.getSkillInfoConfig(skillId);
            if skillInfos then
                local iconName = tostring(skillInfos["f_SkillIcon"]);
                if iconName ~= "0" then
                    self.headBar:GetChild("skillShow").visible = true;
                    self.headBarSkillShow.url = "ui://SkillAtlas/" .. iconName;
                    self.headBarSkillShowAni:Play(function()
                        self.headBar:GetChild("skillShow").visible = false;
                    end)
                    if self.headBarSkillShowEffect.spineAnimation and self.teamIndex == 1 then
                        self.headBarSkillShowEffect.visible = true;
                        self.headBarSkillShowEffect.spineAnimation.state:SetAnimation(0, "idle", false);
                    else
                        self.headBarSkillShowEffect.visible = false;
                    end
                end
            end
            local effect = self.headBar:GetChild("n12");
            effect.visible = true;
            local effectShow = effect.spineAnimation.state;
            effectShow:SetAnimation(0, "idle", false);
            local idleAniTime = effectShow.Data.SkeletonData:FindAnimation("idle").Duration;
            self.ubattletimer = ubattletimer.timeCall(function()
                effect.visible = false;
                ubattletimer.remove(self.ubattletimer);
            end, idleAniTime * 1000)
        end
    end
end

function Entity:setAfterImageOne(skillId)
    local v = (G.dataTable["t_effect2"] or {})[tostring(skillId)];
    if v then
        local color = v.f_Color;
        if self.teamIndex == 1 then
            --color = v.f_Color -- decodeJsonStrToTabel(v.f_Color)
        else
            if v.f_ColorEnemy then
                color = v.f_ColorEnemy;
            end
        end

        local outlineColor = Color(color[1], color[2], color[3], color[4]); --v.f_Color

        local originalSpineGo = self.skeletonAnimationTrans.gameObject;

        --f_RecourseName没用到
        local maxTime = v.f_MaxTime;--需要出现残影的时间段
        local internalTime = v.f_Internal;--残影出现间隔
        local durationTime = v.f_Duration;--残影存在时间
        self.afterImageTab = {};
        for i = 1, maxTime / internalTime do
            -- Util.WaitForSeconds(function()
            --     if self and not HelperFunc.IsNull(originalSpineGo) and not self.isDead and not self.isDeading then
            --         local imgGo = Util.ShowAfterimageOneByOne(self.model .. self.teamIndex, originalSpineGo, outlineColor, durationTime / EnumConst.THOUSANDTH, v.f_AnimationName, (i - 1) * internalTime * 30 / EnumConst.THOUSANDTH);--按一秒30帧算，用延迟算帧
            --         table.insert(self.afterImageTab, imgGo);
            --     end
            -- end, tonumber((i - 1) * internalTime / EnumConst.THOUSANDTH));
            ubattletimer.delayCall(function()
                if self and not HelperFunc.IsNull(originalSpineGo) and not self.isDead and not self.isDeading then
                    local imgGo = Util.ShowAfterimageOneByOne(self.model .. self.teamIndex, originalSpineGo, outlineColor, durationTime / EnumConst.THOUSANDTH, v.f_AnimationName, (i - 1) * internalTime * 30 / EnumConst.THOUSANDTH) --按一秒30帧算，用延迟算帧
                    table.insert(self.afterImageTab, imgGo)
                end
            end, tonumber((i - 1) * internalTime))
        end

    end

end
---@class 击飞落地，重置位置，击飞时间到、死亡、结束战斗时调用
function Entity:recoverPosition()
    if self.roleObj and self.hitShowOriginalPosition then
        Util.Lua_SetLocalPositionXYZ(self.roleObj, self.roleObj.transform.localPosition.x, self.hitShowOriginalPosition.y, self.hitShowOriginalPosition.z);
    end
end
--设置渐隐 单位秒
function Entity:setFadeTime(time)
    self.fadeTime = time;
    self.curFadeTime = time;
end